home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / x11 / video / xevil-1.000 / xevil-1 / physical.C < prev    next >
C/C++ Source or Header  |  1995-08-21  |  84KB  |  4,217 lines

  1. // "physical.C"
  2. /*    Copyright (C) 1994  Steve Hardt
  3.  
  4.     This program is free software; you can redistribute it and/or modify
  5.     it under the terms of the GNU General Public License as published by
  6.     the Free Software Foundation; either version 1, or (at your option)
  7.     any later version.
  8.  
  9.     This program is distributed in the hope that it will be useful,
  10.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.     GNU General Public License for more details.
  13.  
  14.     You should have received a copy of the GNU General Public License
  15.     along with this program; if not, write to the Free Software
  16.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18.     Steve Hardt 
  19.     hardts@athena.mit.edu hardts@media.mit.edu
  20.     hardts@r4002.3dem.bioch.bcm.tmc.edu
  21.     2043 McClendon
  22.     Houston, TX 77030
  23. */
  24.  
  25. #ifndef NO_PRAGMAS
  26. #pragma implementation "physical.h"
  27. #endif
  28.  
  29.  
  30. // Include Files
  31. #include <iostream.h>
  32.  
  33. extern "C" {
  34. #include <string.h>
  35. }
  36.  
  37. #include <strstream.h>
  38.  
  39. #include "utils.h"
  40. #include "coord.h"
  41. #include "area.h"
  42. #include "world.h"
  43. #include "id.h"
  44. #include "intel.h"
  45. #include "locator.h"
  46. #include "physical.h"
  47. #include "actual.h"
  48.  
  49.  
  50. // Defines
  51. #define GRAVITY 2
  52. #define PUSH_OFF 3
  53. #define VEL_SMALL 1
  54. #define MOVING_ANIM_TIME 2
  55. #define MOVING_EXTRA_VEL_MAX 9
  56. #define FALLING_VEL_MAX 12
  57. #define HEAVY_DAMAGE_VEL 3
  58. #define ITEM_CAN_TAKE_TIME 15
  59. #define ITEM_DROP_OFFSET_WIDTH 20
  60. #define ITEM_DROP_OFFSET_HEIGHT 20
  61. #define EXTRA_VEL_DAMP 1
  62. #define DROP_SPEED 2
  63. #define FIGHTER_SLIDE_TIME 4
  64. #define SHOT_OFFSET 19
  65. #define HEAT_MAX 25
  66. #define FLYING_GRAV_VEL_CUTOFF 1
  67. #define CORPSE_TIME 140
  68. #define FLASH_TIME 5
  69. #define TOUCHABLE_RADIUS 20 //11 //10
  70.  
  71.  
  72.  
  73. //// Functions
  74. Physical::Physical(const PhysicalContext &p_c,WorldP w,LocatorP l) 
  75. {
  76.   idValid = False;
  77.   world = w;
  78.   locator = l;
  79.   command = IT_NO_COMMAND;
  80.   pc = &p_c;
  81.   health = healthNext = pc->health;
  82.   mass = massNext = pc->mass;
  83.   dontCollide = NULL;
  84.   intel = NULL;
  85.   if (! staticValid)
  86.     init_static();
  87.   deleteMe = False;
  88.   mapped = mappedNext = True;
  89.   noDeathDelete = False;
  90.   dieCalled = False;
  91.   heat = heatNext = 0;
  92.   previousHeatWasSecondary = False;
  93.  
  94.   // Add 1 to FLASH_TIME to draw for proper number of turns.
  95.   Timer t(FLASH_TIME + 1);
  96.   flashTimer = t;
  97.   quietDeath = False;
  98. }
  99.  
  100.  
  101.  
  102.  Physical::Physical()
  103. {
  104.   assert(0);
  105. }
  106.  
  107.  
  108.  
  109. Physical::~Physical() 
  110. {}
  111.  
  112.  
  113.  
  114. Dir Physical::get_dir() 
  115. {
  116.   return CO_air;
  117. }
  118.  
  119.  
  120.  
  121. int Physical::get_drawing_level()
  122. {
  123.   return 1;
  124. }
  125.  
  126.  
  127.  
  128. Vel Physical::get_vel() // Returns (0,0)
  129. {
  130.   Vel vel; 
  131.   return vel;
  132.  
  133.  
  134.  
  135. Boolean Physical::is_moving() 
  136. {
  137.   return False;
  138. }
  139.  
  140.  
  141.  
  142. Boolean Physical::is_shot() 
  143. {
  144.   return False;
  145. }
  146.  
  147.  
  148.  
  149. Boolean Physical::is_item() 
  150. {
  151.   return False;
  152. }
  153.  
  154.  
  155.  
  156. Boolean Physical::is_shield()
  157. {
  158.   return False;
  159. }
  160.  
  161.  
  162.  
  163. Boolean Physical::is_bomb()
  164. {
  165.   return False;
  166. }
  167.  
  168.  
  169.  
  170. Boolean Physical::is_weapon() 
  171. {
  172.   return False;
  173. }
  174.  
  175.  
  176.  
  177. Boolean Physical::is_cutter() 
  178. {
  179.   return False;
  180. }
  181.  
  182.  
  183.  
  184. Boolean Physical::is_gun() 
  185. {
  186.   return False;
  187. }
  188.  
  189.  
  190.  
  191. Boolean Physical::is_creature() 
  192. {
  193.   return False;
  194. }
  195.  
  196.  
  197.  
  198. Boolean Physical::is_suicide()
  199. {
  200.   return False;
  201. }
  202.  
  203.  
  204.  
  205. Boolean Physical::is_user() 
  206. {
  207.   return False;
  208. }
  209.  
  210.  
  211.  
  212. Boolean Physical::is_fighter() 
  213. {
  214.   return False;
  215. }
  216.  
  217.  
  218.  
  219. Boolean Physical::is_walking() 
  220. {
  221.   return False;
  222. }
  223.  
  224.  
  225.  
  226. Boolean Physical::is_sticky() 
  227. {
  228.   return False;
  229. }
  230.  
  231.  
  232.  
  233. Boolean Physical::is_flying()
  234. {
  235.   return False;
  236. }
  237.  
  238.  
  239.  
  240. Boolean Physical::is_built_in()
  241. {
  242.   return False;
  243. }
  244.  
  245.  
  246.  
  247. Boolean Physical::prickly()
  248. {
  249.   return False;
  250. }
  251.  
  252.  
  253.  
  254. Boolean Physical::collidable() 
  255. {
  256.   return True;
  257. }
  258.  
  259.  
  260.  
  261. PHsig Physical::get_id(Id &outside_id)
  262. {
  263.   if (! idValid)
  264.     return PH_NOT_SET;
  265.  
  266.   outside_id = id;
  267.   return PH_NO_SIG;
  268. }
  269.  
  270.  
  271.  
  272. PHsig Physical::set_id(const Id &new_id)
  273. {
  274.   id = new_id;
  275.  
  276.   if (idValid)
  277.     return PH_ID_CHANGED;
  278.  
  279.   idValid = True;
  280.   return PH_NO_SIG;
  281. }
  282.  
  283.  
  284.  
  285. void Physical::heal()
  286. {
  287.   set_health_next(get_health_max());
  288. }
  289.  
  290.  
  291.  
  292. void Physical::set_mapped_next(Boolean val)
  293. {
  294.   mappedNext = val;
  295. }
  296.  
  297.  
  298.  
  299. void Physical::flash()
  300. {
  301.   flashTimer.set();
  302. }
  303.  
  304.  
  305.  
  306. void Physical::corporeal_attack(PhysicalP,int damage) 
  307. {
  308.   healthNext = health - damage;
  309. }
  310.  
  311.  
  312.  
  313. void Physical::heat_attack(PhysicalP,int h,Boolean secondary)
  314. {
  315.   assert(h >= 0);
  316.   if (! (secondary && previousHeatWasSecondary)) // Don't propagate fires.
  317.     {
  318.       heatNext = heat + h;
  319.       
  320.       if (heatNext > HEAT_MAX)
  321.     heatNext = HEAT_MAX;
  322.       
  323.       if (heat == 0 && heatNext > 0)
  324.     {
  325.       LocatorP l = get_locator();
  326.       ostrstream str;
  327.       str << identify() << " is on fire." << ends;
  328.       locator->message_enq(str.str());
  329.     }
  330.     }
  331.   previousHeatWasSecondary = secondary;
  332. }
  333.  
  334.  
  335.  
  336. Boolean Physical::swap_protect()
  337. {
  338.   return False;
  339. }
  340.  
  341.  
  342.  
  343. Boolean Physical::frog_protect()
  344. {
  345.   return False;
  346. }
  347.  
  348.  
  349.  
  350. void Physical::avoid(PhysicalP) {}
  351.  
  352.  
  353.  
  354. void Physical::collide(PhysicalP) {}
  355.  
  356.  
  357.  
  358. void Physical::act()
  359. {  
  360.   const Area &area = get_area();
  361.  
  362. /* This check is now done inside the locator.
  363.   if (alive() && !world->inside(area.middle_wsquare()))
  364.     {
  365.       LocatorP locator = get_locator();
  366.       ostrstream msg;
  367.       msg << identify() << " has been knocked out of the world so is dead." <<
  368.     ends;
  369.       locator->message_enq(msg.str()); 
  370.       
  371.       kill_self();
  372.       } */
  373.  
  374.   if (heatNext > 0)
  375.     {
  376.       Pos pos;
  377.       Size size;
  378.       area.get_rect(pos,size);
  379.       pos.x += Utils::choose(size.width);
  380.       // Start fire in upper-half.
  381.       if (size.height > 1)
  382.     pos.y += Utils::choose((int)(size.height * .5)); 
  383.  
  384.       LocatorP locator = get_locator();
  385.       PhysicalP fire = new Fire(get_world(),locator,pos);
  386.       fire->set_dont_collide(this);
  387.       locator->add(fire);
  388.       heatNext--;
  389.  
  390.       healthNext -= Fire::get_damage();
  391.     }
  392. }
  393.  
  394.  
  395.  
  396. void Physical::set_quiet_death()
  397. {
  398.   quietDeath = True;
  399. }
  400.  
  401.  
  402.  
  403. void Physical::update()
  404. {
  405.   mass = massNext;
  406.  
  407.   command = IT_NO_COMMAND;
  408.  
  409.   // Fire damage is now in Physical::act
  410.  
  411.   health = healthNext;
  412.   mapped = mappedNext;
  413.   heat = heatNext;
  414.   flashTimer.clock();
  415.  
  416. }
  417.  
  418.  
  419.  
  420. void Physical::die() 
  421. {
  422.   assert(!dieCalled && healthNext < 0 && health >= 0);
  423.   dieCalled = True;
  424.  
  425.   if (intel) 
  426.     intel->die();
  427.   intel = NULL;
  428.  
  429.   if (!noDeathDelete)
  430.     set_delete_me();
  431. }
  432.  
  433.  
  434.  
  435. int Physical::get_weapons_num()
  436. {
  437.   return 0;
  438. }
  439.  
  440.  
  441.  
  442. int Physical::get_items_num()
  443. {
  444.   return 0;
  445. }
  446.  
  447.  
  448.  
  449. PhysicalP Physical::get_weapon(int)
  450. {
  451.   return NULL;
  452. }
  453.  
  454.  
  455.  
  456. PhysicalP Physical::get_item(int)
  457. {
  458.   return NULL;
  459. }
  460.  
  461.  
  462.  
  463. PhysicalP Physical::get_weapon_current()
  464. {
  465.   return NULL;
  466. }
  467.  
  468.  
  469.  
  470. PhysicalP Physical::get_item_current()
  471. {
  472.   return NULL;
  473. }
  474.  
  475.  
  476.  
  477. Boolean Physical::ready()
  478. {
  479.   return False;
  480. }
  481.  
  482.  
  483.  
  484. void Physical::init_static()
  485. {
  486.   // CO_air_* is not really a unit.
  487.  
  488.   unitAccs[CO_center_R].ddx = 1.0;
  489.   unitAccs[CO_center_L].ddx = -1.0;
  490.   unitAccs[CO_air_R].ddx = .4;
  491.   unitAccs[CO_air_L].ddx = -.4;
  492.   unitAccs[CO_air_R].ddy = unitAccs[CO_air_L].ddy = -1.0;  // -0.95
  493.   unitAccs[CO_air_UP].ddy = -1.0;
  494.   unitAccs[CO_air_DN].ddy = 1.0;
  495.  
  496.   unitAccs[CO_center_R].ddy = unitAccs[CO_center_L].ddy = 
  497.       unitAccs[CO_air].ddy = unitAccs[CO_air].ddx = 
  498.     unitAccs[CO_center].ddx = 
  499.       unitAccs[CO_center].ddy = unitAccs[CO_air_UP].ddx = 
  500.     unitAccs[CO_air_DN].ddx = 
  501.       0.0;
  502.  
  503.   unitAccs[CO_r].ddx = unitAccs[CO_r].ddy =
  504.       unitAccs[CO_dn].ddx = unitAccs[CO_dn].ddy =
  505.     unitAccs[CO_l].ddx = unitAccs[CO_l].ddy =
  506.       unitAccs[CO_up].ddx = unitAccs[CO_up].ddy =
  507.         0.0;
  508.   
  509.   unitAccs[CO_r_DN].ddx = unitAccs[CO_r_UP].ddx =
  510.     unitAccs[CO_dn_R].ddy = unitAccs[CO_dn_L].ddy =
  511.       unitAccs[CO_l_DN].ddx = unitAccs[CO_l_UP].ddx =
  512.     unitAccs[CO_up_R].ddy = unitAccs[CO_up_L].ddy =
  513.       unitAccs[CO_climb_DN].ddx = unitAccs[CO_climb_UP].ddx =
  514.         0.0;
  515.   
  516.   unitAccs[CO_r_DN].ddy = unitAccs[CO_l_DN].ddy = unitAccs[CO_climb_DN].ddy = 
  517.     0.5;
  518.   
  519.   unitAccs[CO_r_UP].ddy = unitAccs[CO_l_UP].ddy = unitAccs[CO_climb_UP].ddy =
  520.     -0.5;
  521.   
  522.   unitAccs[CO_dn_R].ddx = unitAccs[CO_up_R].ddx = 0.5;
  523.   
  524.   unitAccs[CO_dn_L].ddx = unitAccs[CO_up_L].ddx = -0.5;
  525.   
  526.   for (int n = 0; n < 16; n++)
  527.     {
  528.       float theta = M_PI * n / 8.0;
  529.  
  530.       unitAccs[CO_R + n].ddx = cos(theta);
  531.       unitAccs[CO_R + n].ddy = sin(theta);
  532.     }
  533.  
  534.   for (n = 0; n < CO_DIR_MAX; n++)
  535.     unitVels[n] = unitAccs[n];
  536.  
  537.   staticValid = True;
  538. }
  539.  
  540.  
  541.  
  542. Boolean Physical::staticValid = False;
  543. Acc Physical::unitAccs[CO_DIR_MAX];
  544. Vel Physical::unitVels[CO_DIR_MAX];
  545.  
  546.  
  547.  
  548. Protection::Protection(const ProtectionContext &pr_c,ProtectionXdata &x_data,
  549.                WorldP w,LocatorP l,const Area &ar)
  550.   : Physical(pr_c.physicalContext,w,l)
  551. {
  552.   area = areaNext = areaBaseNext = ar;
  553.   delta = 0;
  554.   pXdata = &x_data;
  555.   prc = &pr_c;
  556. }
  557.  
  558.  
  559.  
  560. Boolean Protection::collidable()
  561. {
  562.   return False;
  563. }
  564.  
  565.  
  566.  
  567. const Area &Protection::get_area()
  568. {
  569.   return area;
  570. }
  571.  
  572.  
  573.  
  574. const Area &Protection::get_area_next()
  575. {
  576.   return areaNext;
  577. }
  578.  
  579.  
  580.  
  581. void Protection::follow(const Area &aBaseNext)
  582. {
  583.   areaBaseNext = aBaseNext;
  584.  
  585.   Pos basePos;
  586.   Size baseSize;
  587.   areaBaseNext.get_rect(basePos,baseSize);
  588.   Pos nPos(basePos.x - delta,basePos.y - delta);
  589.   Size nSize;
  590.   nSize.width = baseSize.width + 2 * delta;
  591.   nSize.height = baseSize.height + 2 * delta;
  592.  
  593.   if (nSize.width < 0)
  594.     nSize.width = 0;
  595.   if (nSize.height < 0)
  596.     nSize.height = 0;
  597.  
  598.   Area nArea(AR_RECT,nPos,nSize);
  599.   areaNext = nArea;
  600. }
  601.  
  602.  
  603.  
  604. void Protection::draw(Drawable buffer,Xvars &xvars,int dpyNum,const Area &bufArea)
  605. {
  606.   if (!pXdata->valid)
  607.     init_x(xvars);
  608.  
  609.   Pos pos;
  610.   Size size;
  611.   area.get_rect(pos,size);
  612.   Size offset = area - bufArea;
  613.  
  614.   XSetForeground(xvars.dpy[dpyNum],xvars.gc[dpyNum],pXdata->color[dpyNum]);
  615.   XDrawRectangle(xvars.dpy[dpyNum],buffer,xvars.gc[dpyNum],
  616.          offset.width,offset.height,
  617.          size.width - 1,size.height - 1);
  618.   XSetForeground(xvars.dpy[dpyNum],xvars.gc[dpyNum],xvars.black[dpyNum]);
  619. }
  620.  
  621.  
  622.  
  623. void Protection::act()
  624. {
  625.   delta++;
  626.   if (delta == DELTA_MAX)
  627.     delta = DELTA_MIN;
  628.  
  629.   // Updates areaNext.
  630.   follow(areaBaseNext);
  631.  
  632.   Physical::act();
  633. }
  634.  
  635.  
  636.  
  637. void Protection::update()
  638. {
  639.   area = areaNext;
  640.   
  641.   Physical::update();
  642. }
  643.  
  644.  
  645.  
  646. void Protection::init_x(Xvars &xvars)
  647. {
  648.   assert(!pXdata->valid);
  649.   for (int dpyNum = 0; dpyNum < xvars.dpyMax; dpyNum++)
  650.     pXdata->color[dpyNum] = 
  651.       xvars.allocNamedColor(dpyNum,prc->colorName,xvars.black[dpyNum]);
  652.   pXdata->valid = True;
  653. }
  654.  
  655.  
  656.  
  657. Moving::Moving(const MovingContext &m_c,
  658.         MovingXdata &x_data,
  659.         WorldP w,           
  660.         LocatorP l,
  661.         const Pos &raw_pos,
  662.         Dir dirInitial)
  663.      : Physical(m_c.physicalContext,w,l)
  664. {
  665.   movingXdata = &x_data;
  666.   mc = &m_c;
  667.  
  668.   rawPos = rawPosNext = raw_pos;
  669.   rawPosChanged = False;
  670.   dir = dirNext = dirInitial; /* Don't change.  See Shell. */
  671.  
  672.   if (m_c.animMax[dir])
  673.     movingAnimNum = Utils::choose(m_c.animMax[dir]);
  674.   else
  675.     movingAnimNum = 0;
  676.   
  677.   // offsets[CO_air] and sizes[CO_air] are guaranteed to be set.
  678.   Area nArea(AR_RECT,raw_pos + mc->offsets[dir],mc->sizes[dir]);
  679.   area = areaNext = nArea;
  680.  
  681.   WorldP world = get_world();
  682.   hitWall = hitWallNext = !world->open(area);
  683.   
  684.   extraVelNextSet = False;
  685.  
  686.   assert(context_valid());
  687.  
  688.   // NOTE: protection initializes itself.
  689. };
  690.  
  691.  
  692.  
  693. Moving::Moving()
  694. {
  695.   assert(0);
  696. }
  697.  
  698.  
  699.  
  700. Boolean Moving::is_moving()
  701. {
  702.   return True;
  703. }
  704.  
  705.  
  706.  
  707. const Area &Moving::get_area() 
  708. {
  709.   return area;
  710. }
  711.  
  712.  
  713.  
  714. const Area &Moving::get_area_next() 
  715. {
  716.   return areaNext;
  717. }
  718.  
  719.  
  720.  
  721. Vel Moving::get_vel()
  722. {
  723.   return vel;
  724. }
  725.  
  726.  
  727.  
  728. Dir Moving::get_dir() 
  729. {
  730.   return dir;
  731. }
  732.  
  733.  
  734.  
  735. Id Moving::get_protection()
  736. {
  737.   return protection;
  738. }
  739.  
  740.  
  741.  
  742. void Moving::set_middle_next(const Pos &middleNext)
  743. {
  744.   Pos pos;
  745.   Size size;
  746.   area.get_rect(pos,size);
  747.  
  748.   Pos rPosNext = middleNext - mc->offsets[dir] - 0.5 * size;
  749.  
  750.   /* Important to set rawPosChanged if called before act. */
  751.   set_raw_pos_next(rPosNext);  
  752.  
  753.   /* Only matters if called after act.  Otherwise is just redundant. */
  754.   update_next(); 
  755. }
  756.  
  757.  
  758.  
  759. void Moving::relocate(const Pos &rPos)
  760. {
  761.   assert(area == areaNext);
  762.   assert(dir == dirNext);
  763.   assert(vel == velNext);
  764.   assert(rawPos == rawPosNext);
  765. //  assert(extraVel == extraVelNext);
  766.   assert(hitWall == hitWallNext);
  767.  
  768.   Pos pos;
  769.   Size size;
  770.   area.get_rect(pos,size);
  771.   Size delta = pos - rawPos;
  772.   
  773.   rawPos = rawPosNext = rPos;
  774.   Area nArea(AR_RECT,rawPos + delta,size);
  775.   area = areaNext = nArea;
  776.  
  777.   hitWall = hitWallNext = False;
  778. }
  779.  
  780.  
  781.  
  782. void Moving::set_mapped_next(Boolean val)
  783. {
  784.   LocatorP locator = get_locator();
  785.   PhysicalP p = locator->lookup(protection);
  786.   if (p)
  787.     p->set_mapped_next(val);
  788.  
  789.   Physical::set_mapped_next(val);
  790. }
  791.  
  792.  
  793.  
  794. void Moving::set_protection(const Id &id)
  795. {
  796.   protection = id;
  797. }
  798.  
  799.  
  800.  
  801. void Moving::corporeal_attack(PhysicalP killer,int damage)
  802. {
  803.   // Protection from corporeal attacks.
  804.   LocatorP l = get_locator();
  805.   ProtectionP p = (ProtectionP)l->lookup(protection);
  806.   if (p && p->corporeal_protect(damage))
  807.     return;
  808.  
  809.   Physical::corporeal_attack(killer,damage);
  810. }
  811.  
  812.  
  813.  
  814. void Moving::heat_attack(PhysicalP killer,int h,Boolean secondary)
  815. {
  816.   // Protection from heat.
  817.   LocatorP l = get_locator();
  818.   ProtectionP p = (ProtectionP)l->lookup(protection);
  819.   if (p && p->heat_protect(h,secondary))
  820.     return;
  821.  
  822.   Physical::heat_attack(killer,h,secondary);
  823. }
  824.  
  825.  
  826.  
  827. void Moving::act()
  828. {
  829.   // Note: no restrictions on vel.
  830.   extraVel.limit(MOVING_EXTRA_VEL_MAX);
  831.   Vel sumVel = velNext + extraVel;
  832.   extraVel.damp(EXTRA_VEL_DAMP);
  833.   
  834.   if (!rawPosChanged)
  835.     rawPosNext = rawPos + sumVel;
  836.   
  837.   update_next();
  838.   
  839.  Physical::act();
  840. }
  841.  
  842.  
  843.  
  844. void Moving::update()
  845. {
  846.   rawPos = rawPosNext;  
  847.   rawPosChanged = False;
  848.   
  849.   area = areaNext;
  850.  
  851.   if(mc->animMax[dir])
  852.     {
  853.       if (animTimer.ready())
  854.     {
  855.       movingAnimNum = (movingAnimNum + 1) % mc->animMax[dir];
  856.       animTimer.set(MOVING_ANIM_TIME);
  857.     }
  858.       animTimer.clock();
  859.     }
  860.  
  861.   if (dir != dirNext)
  862.     movingAnimNum = 0;
  863.   dir = dirNext;
  864.   
  865.   hitWall = hitWallNext;
  866.   vel = velNext;  
  867.  
  868.   if (extraVelNextSet)
  869.     {
  870.       extraVel = extraVelNext;
  871.       extraVelNextSet = False;
  872.     }
  873.   
  874.  Physical::update();
  875. }
  876.  
  877.  
  878.  
  879. void Moving::draw(Drawable buffer,Xvars &xvars,int dpyNum,const Area &bufArea)
  880. {    
  881.   if (!movingXdata->valid)
  882.     init_x(xvars);
  883.  
  884.   Pos pos;
  885.   Size size;
  886.   area.get_rect(pos,size);
  887.   Size offset = area - bufArea;
  888.  
  889.   Pixmap pixmap,mask;
  890.   get_pixmap_mask(dpyNum,pixmap,mask,dir,movingAnimNum);
  891.   
  892.   XSetClipMask(xvars.dpy[dpyNum],xvars.gc[dpyNum],mask);
  893.   XSetClipOrigin(xvars.dpy[dpyNum],xvars.gc[dpyNum],offset.width,offset.height);
  894.  
  895.   XCopyArea(xvars.dpy[dpyNum],pixmap,
  896.         buffer,xvars.gc[dpyNum],0,0,
  897.         size.width,size.height,
  898.         offset.width,offset.height);
  899.   
  900.   // Restore gc to initial state.
  901.   XSetClipMask(xvars.dpy[dpyNum],xvars.gc[dpyNum],None);
  902.   XSetClipOrigin(xvars.dpy[dpyNum],xvars.gc[dpyNum],0,0);
  903.  
  904.  
  905.   // Draw outline around object if controlled by a Human or if a slave to
  906.   // a Human master.
  907.   IntelP intel = get_intel();
  908.   IntelP master = NULL;
  909.   Boolean drawOutline = False;
  910.   if (intel)
  911.     {
  912.       if (intel->is_human())
  913.     drawOutline = True;
  914.       else
  915.     {
  916.       LocatorP locator = get_locator();
  917.       master = 
  918.         locator->lookup(((MachineP)intel)->get_master_intel_id());
  919.       if (master && master->is_human())
  920.         drawOutline = True;
  921.     }
  922.     }
  923.   if (drawOutline)
  924.     {
  925.       ColorNum colorNum;
  926.       if (intel->is_human())
  927.     colorNum = ((HumanP)intel)->get_color_num();
  928.       else
  929.     {
  930.       assert(master && master->is_human());
  931.       colorNum = ((HumanP)master)->get_color_num();
  932.     }
  933.       
  934.       XSetForeground(xvars.dpy[dpyNum],xvars.gc[dpyNum],
  935.              xvars.humanColors[dpyNum][colorNum]);
  936.       XPoint points[12];
  937.  
  938.       points[0].x = offset.width;
  939.       points[0].y = offset.height;
  940.       
  941.       points[1].x = offset.width + 1;
  942.       points[1].y = offset.height;
  943.       
  944.       points[2].x = offset.width;
  945.       points[2].y = offset.height + 1;
  946.       
  947.  
  948.       points[3].x = offset.width + size.width - 1;
  949.       points[3].y = offset.height;
  950.       
  951.       points[4].x = offset.width + size.width - 2;
  952.       points[4].y = offset.height;
  953.       
  954.       points[5].x = offset.width + size.width - 1;
  955.       points[5].y = offset.height + 1;
  956.       
  957.  
  958.       points[6].x = offset.width;
  959.       points[6].y = offset.height + size.height - 1;
  960.       
  961.       points[7].x = offset.width;
  962.       points[7].y = offset.height + size.height - 2;
  963.       
  964.       points[8].x = offset.width + 1;
  965.       points[8].y = offset.height + size.height - 1;
  966.       
  967.  
  968.       points[9].x = offset.width + size.width - 1;
  969.       points[9].y = offset.height + size.height - 1;
  970.  
  971.       points[10].x = offset.width + size.width - 2;
  972.       points[10].y = offset.height + size.height - 1;
  973.  
  974.       points[11].x = offset.width + size.width - 1;
  975.       points[11].y = offset.height + size.height - 2;
  976.  
  977.       XDrawPoints(xvars.dpy[dpyNum],buffer,xvars.gc[dpyNum],points,
  978.           12,CoordModeOrigin);
  979.       XSetForeground(xvars.dpy[dpyNum],xvars.gc[dpyNum],xvars.black[dpyNum]);
  980.     }
  981. }
  982.  
  983.  
  984.  
  985. void Moving::avoid(PhysicalP other)
  986. {
  987.   const Area &otherArea = other->get_area();
  988.   Size offset = area.avoid_no_up(otherArea);
  989.   set_raw_pos_next(rawPos + offset);
  990. }
  991.  
  992.  
  993.  
  994. void Moving::collide(PhysicalP other)
  995. {
  996.   Mass m1 = this->get_mass();
  997.   Vel v1 = this->get_vel();
  998.   Mass m2 = other->get_mass();
  999.   Vel v2 = other->get_vel();
  1000.  
  1001.   if (m1 > 0 && m2 > 0) // Don`t have collisions with objects of zero mass.
  1002.     {
  1003.       Vel newVel(compute_collision(m1,v1.dx,m2,v2.dx),
  1004.          compute_collision(m1,v1.dy,m2,v2.dy)); 
  1005.       set_vel_next(0);
  1006.       extraVel = newVel;
  1007.     }
  1008. }
  1009.  
  1010.  
  1011.  
  1012. void Moving::die()
  1013. {
  1014.   LocatorP locator = get_locator();
  1015.   PhysicalP p = locator->lookup(protection);
  1016.   // Must be careful about killing p because we are in the die() phase.
  1017.   if (p && !p->die_called())
  1018.     {
  1019.       p->kill_self();
  1020.       p->die();
  1021.     }
  1022.   Physical::die();
  1023.  
  1024.  
  1025.  
  1026. void Moving::update_next()
  1027. {
  1028.   // Compute areaNext and hitWallNext.  May modify rawPosNext or dirNext.
  1029.   Size size,off_set;
  1030.   get_size_offset_next(size,off_set,dirNext);
  1031.   Area first_guess(AR_RECT,rawPosNext + off_set,size);
  1032.     
  1033.   WorldP world = get_world();
  1034.   Size offset;
  1035.  
  1036.   // Should we use velNext or vel?
  1037.   switch (world->open_offset(offset,first_guess,vel)) {
  1038.   case W_NO_SIG:
  1039.     areaNext = first_guess;
  1040.     hitWallNext = False;
  1041.     break;
  1042.     
  1043.   case W_CLOSE:
  1044.     rawPosNext = rawPosNext + offset;
  1045.     areaNext = first_guess;
  1046.     areaNext.shift(offset);
  1047.     hitWallNext = True;
  1048.     /* Doesn't set velocity to 0. */
  1049.     break;
  1050.     
  1051.   case W_CLOSE_BAD:
  1052.     rawPosNext = rawPosNext + offset;
  1053.     areaNext = first_guess;
  1054.     areaNext.shift(offset);
  1055.     hitWallNext = True;
  1056.     set_vel_next(0); // ????
  1057.     break;
  1058.     
  1059.   case W_FAILURE:
  1060.     /* Abort all changes to area, rawPos, or dir. */
  1061.     areaNext = area;
  1062.     rawPosNext = rawPos;
  1063.     dirNext = dir; 
  1064.     hitWallNext = True;
  1065.     set_vel_next(0); // ??? Will help? 8/18/94
  1066.     break;
  1067.   }
  1068.  
  1069.   LocatorP locator = get_locator();
  1070.   ProtectionP protectionP = (ProtectionP)locator->lookup(protection);
  1071.   if (protectionP)
  1072.     protectionP->follow(areaNext);
  1073. }
  1074.   
  1075.  
  1076.  
  1077. void Moving::get_pixmap_mask(int dpyNum,Pixmap &pixmap,Pixmap &mask,
  1078.                  Dir dir,int animNum)
  1079. {
  1080.   pixmap = movingXdata->pixmaps[dpyNum][dir][animNum];
  1081.   mask = movingXdata->masks[dpyNum][dir][animNum];
  1082. }
  1083.  
  1084.  
  1085.  
  1086. void Moving::get_size_offset_next(Size &size,Size &offset,Dir)
  1087. {
  1088.   size = mc->sizes[dirNext];
  1089.   offset = mc->offsets[dirNext];
  1090. }
  1091.  
  1092.  
  1093.  
  1094. void Moving::init_x(Xvars &xvars) 
  1095. {
  1096.   assert(movingXdata->valid == False);
  1097.  
  1098.   for (int dpyNum = 0; dpyNum < xvars.dpyMax; dpyNum++)
  1099.     for (int n = 0; n < CO_DIR_MAX; n++)
  1100.       for (int m = 0; m < mc->animMax[n]; m++)
  1101.     {
  1102.       movingXdata->pixmaps[dpyNum][n][m] = 
  1103.         XCreatePixmapFromBitmapData(xvars.dpy[dpyNum],xvars.root[dpyNum],
  1104.                     mc->pixmapBits[n][m],
  1105.                     mc->sizes[n].width,mc->sizes[n].height,
  1106.                     xvars.
  1107.                     allocNamedColor(dpyNum,
  1108.                             mc->foreColorName,
  1109.                             mc->foreWhiteDefault ? 
  1110.                             xvars.white[dpyNum]:
  1111.                             xvars.black[dpyNum]),
  1112.                     xvars.
  1113.                     allocNamedColor(dpyNum,
  1114.                             mc->backColorName,
  1115.                             mc->backWhiteDefault ?
  1116.                             xvars.white[dpyNum]: 
  1117.                             xvars.black[dpyNum]),
  1118.                     xvars.depth[dpyNum]);
  1119.       movingXdata->masks[dpyNum][n][m] = 
  1120.         XCreateBitmapFromData(xvars.dpy[dpyNum],xvars.root[dpyNum],
  1121.                   mc->maskBits[n][m],
  1122.                   mc->sizes[n].width,mc->sizes[n].height);
  1123.     }
  1124.   movingXdata->valid = True;
  1125. }
  1126.  
  1127.  
  1128.  
  1129. Boolean Moving::context_valid()
  1130. {
  1131. /*  if (!(mc->sizes[CO_climb] == mc->sizes[CO_climb_UP]) ||
  1132.       !(mc->sizes[CO_climb] == mc->sizes[CO_climb_DN]))
  1133.     return False; */ /* frog.bitmaps */
  1134.  
  1135.   // See Moving::corner
  1136.   if (!(mc->sizes[CO_r] == mc->sizes[CO_r_UP]) ||
  1137.       !(mc->sizes[CO_r] == mc->sizes[CO_r_DN]) ||
  1138.       !(mc->sizes[CO_dn] == mc->sizes[CO_dn_R]) ||
  1139.       !(mc->sizes[CO_dn] == mc->sizes[CO_dn_L]) ||
  1140.       !(mc->sizes[CO_l] == mc->sizes[CO_l_UP]) ||
  1141.       !(mc->sizes[CO_l] == mc->sizes[CO_l_DN]) ||
  1142.       !(mc->sizes[CO_up] == mc->sizes[CO_up_R]) ||
  1143.       !(mc->sizes[CO_up] == mc->sizes[CO_up_L]))
  1144.     return False;
  1145.   
  1146.   // Objects do not need CO_air
  1147.  
  1148.  
  1149.   for (int dir = 0; dir < CO_DIR_MAX; dir++)
  1150.     {
  1151.       if (mc->animMax[dir] < 0)
  1152.     return False;
  1153.       for (int m = 0; m < mc->animMax[dir]; m++)
  1154.     if ((mc->pixmapBits[dir][m] == 0) || (mc->maskBits[dir][m] == 0))
  1155.       return False;
  1156.     }
  1157.   return True;
  1158. }
  1159.  
  1160.  
  1161.  
  1162. float Moving::compute_collision(Mass m1,float v1,Mass m2,float v2)
  1163. {
  1164.   assert(m1 > 0 && m2 > 0);
  1165.  
  1166.   float A = m1 * v1 + m2 * v2;
  1167.   float B = 0.5 * m1 * v1 * v1 + 0.5 * m2 * v2 * v2;
  1168.   
  1169.   float a = (m1*m2 + m1*m1);
  1170.   float b = -2 * m1 * A;
  1171.   float c = A * A - 2 * m2 * B;
  1172.  
  1173.   float disc = b * b - 4 * a * c;
  1174.  
  1175.   /* Hack.  If the discriminant is negative for some reason, returning 0 
  1176.      shouldn't do too much damage. */
  1177.   if (disc < 0)
  1178.     return 0;
  1179.  
  1180.   float v1_1 = (-b + sqrt(disc))/ (2 * a);
  1181.   float v1_2 = (-b - sqrt(disc))/ (2 * a);
  1182.   
  1183.   return fabs(v1_1 - v1) > fabs(v1_2 - v1) ? v1_1 : v1_2;
  1184. }
  1185.  
  1186.  
  1187.  
  1188. Shot::Shot(const ShotContext &s_c,ShotXdata &xdata,WorldP w,LocatorP l,
  1189.        const Pos &p,const Id &shoot_er,
  1190.        Dir shotDir,Dir movingDir) 
  1191.      : Moving(s_c.movingContext,xdata,w,l,p,movingDir)
  1192. {
  1193.   stats.add_creation();
  1194.  
  1195.   context = &s_c;
  1196.   shooter = shoot_er;
  1197.  
  1198.   const Vel *unitVels = get_unit_vels();
  1199.   set_vel_next(context->speed * unitVels[shotDir]);
  1200.   if (hit_wall())
  1201.     kill_self();
  1202. }
  1203.  
  1204.  
  1205.  
  1206. Boolean Shot::is_shot()
  1207. {
  1208.   return True;
  1209. }
  1210.  
  1211.  
  1212.  
  1213. void Shot::avoid(PhysicalP) {}
  1214.  
  1215.  
  1216.  
  1217. void Shot::collide(PhysicalP other)
  1218. {
  1219.   if (other->is_shot())
  1220.     return;
  1221.  
  1222.   PhysicalP p;
  1223.   LocatorP locator = get_locator();
  1224.   if (locator->lookup(p,shooter) == OL_NO_SIG)
  1225.     other->corporeal_attack(p,context->damage);
  1226.   else
  1227.     other->corporeal_attack(NULL,context->damage);
  1228.  
  1229.   kill_self();
  1230. }
  1231.  
  1232.  
  1233.  
  1234. void Shot::act()
  1235. {
  1236.   if (hit_wall())  // Used to be hit_wall_next() but lances died too soon.
  1237.     kill_self();
  1238.  
  1239.   Moving::act();
  1240. }
  1241.  
  1242.  
  1243.  
  1244. Stats Shot::stats;
  1245.  
  1246.  
  1247.  
  1248. Falling::Falling(const FallingContext &f_c,FallingXdata &x_data,
  1249.          WorldP w,LocatorP l,const Pos &raw_pos,Dir dirInitial) :
  1250.        Moving(f_c.movingContext,x_data,w,l,raw_pos,dirInitial) 
  1251. {}
  1252.  
  1253.  
  1254.  
  1255. void Falling::act()
  1256. {
  1257.   Touching touching;
  1258.   Hanging hanging;
  1259.  
  1260.   const Area &area = get_area();
  1261.   WorldP world = get_world();
  1262.   world->touchingHanging(touching,hanging,area);
  1263.  
  1264.   // Account for gravity.  
  1265.   Vel velNext = get_vel_next();
  1266.   if (touching != CO_dn) 
  1267.     velNext.dy += GRAVITY; 
  1268.   else 
  1269.     velNext.dy = 0;
  1270.  
  1271.   if (touching == CO_r || touching == CO_l)
  1272.     velNext.dx = 0;
  1273.  
  1274.   velNext.limit(FALLING_VEL_MAX);
  1275.   set_vel_next(velNext);
  1276.  
  1277.   Moving::act();
  1278. }
  1279.  
  1280.  
  1281.  
  1282. Touchable::Touchable(const TouchableContext &t_c,TouchableXdata &x_data,
  1283.              WorldP w,LocatorP l,const Pos &raw_pos) 
  1284. : Falling(t_c.fallingContext,x_data,w,l,raw_pos) 
  1285. {
  1286.   touched = False;
  1287.   context = &t_c;
  1288. }
  1289.  
  1290.  
  1291.  
  1292. int Touchable::get_drawing_level()
  1293. {
  1294.   return 0;
  1295. }
  1296.  
  1297.  
  1298.  
  1299. Boolean Touchable::collidable()
  1300. {
  1301.   return False;
  1302. }
  1303.  
  1304.  
  1305.  
  1306. void Touchable::act()
  1307. {
  1308.   if (!touched)
  1309.     {
  1310.       PhysicalP nearby[OL_NEARBY_MAX];
  1311.       int nItems;
  1312.       LocatorP l = get_locator();
  1313.       l->get_nearby(nearby,nItems,this,TOUCHABLE_RADIUS);
  1314.       const Area &area = get_area();
  1315.       
  1316.       for (int n = 0; n < nItems; n++)
  1317.     {
  1318.       IntelP intel = nearby[n]->get_intel();
  1319.       if (intel && intel->is_human())
  1320.         {
  1321.           const Area &otherArea = nearby[n]->get_area();
  1322.           if (area.overlap(otherArea))
  1323.         touched = True;
  1324.         }
  1325.     }
  1326.     }
  1327.  
  1328.   Falling::act();
  1329. }
  1330.  
  1331.  
  1332.  
  1333. Heavy::Heavy(const HeavyContext &h_c,HeavyXdata &x_data,
  1334.          WorldP w,LocatorP l,const Pos &raw_pos) 
  1335.      : Falling(h_c.fallingContext,x_data,w,l,raw_pos) 
  1336. {
  1337.   context = &h_c;
  1338. }
  1339.  
  1340.  
  1341.  
  1342. void Heavy::collide(PhysicalP other)
  1343. {
  1344.   const Vel &vel = get_vel();
  1345.   if (vel.dy >= HEAVY_DAMAGE_VEL)
  1346.     {
  1347.       const Area &area = get_area();
  1348.       const Area &otherArea = other->get_area();
  1349.       const Pos &otherMiddle = otherArea.get_middle();
  1350.  
  1351.       Dir dirTo = area.dir_to(otherMiddle);
  1352.       if ((dirTo == CO_DN_R) || (dirTo == CO_DN) || (dirTo == CO_DN_L))
  1353.     other->corporeal_attack(this,context->damage);
  1354.     }
  1355.   Falling::collide(other);
  1356. }
  1357.  
  1358.  
  1359.  
  1360. Item::Item(const ItemContext &c_x,
  1361.        ItemXdata &x_data,
  1362.        WorldP w,
  1363.        LocatorP l,
  1364.        const Pos &pos) :
  1365.        Falling(c_x.fallingContext,x_data,w,l,pos) 
  1366. {
  1367.   Timer ntimer(ITEM_CAN_TAKE_TIME);
  1368.   canTake = ntimer;
  1369.   dieMessage = DESTROYED;
  1370.   held = False;
  1371.   context = &c_x;
  1372.   cantTake = False;
  1373. }
  1374.  
  1375.  
  1376.  
  1377. int Item::get_drawing_level()
  1378. {
  1379.   return 2;
  1380. }
  1381.  
  1382.  
  1383.  
  1384. Id Item::get_holder_id()
  1385. {
  1386.   if (held)
  1387.     return holderId;
  1388.   else
  1389.     {
  1390.       Id invalid;
  1391.       return invalid;
  1392.     }
  1393. }
  1394.  
  1395.  
  1396.  
  1397. void Item::set_quiet_death()
  1398. {
  1399.   dieMessage = NONE;
  1400.   Falling::set_quiet_death();
  1401. }
  1402.  
  1403.  
  1404.  
  1405. void Item::follow_user(const Pos &pos,Dir)
  1406. {
  1407.   set_middle_next(pos);
  1408. }
  1409.  
  1410.  
  1411.  
  1412. void Item::taken(PhysicalP p) 
  1413. {
  1414.   assert(!held);
  1415.   assert(!cantTake);
  1416.   held = True; 
  1417.   holderId = p->get_id();
  1418.   set_mapped_next(False);
  1419. }
  1420.  
  1421.  
  1422.  
  1423. void Item::dropped(PhysicalP dropper)
  1424. {
  1425.   // Can happen in update phase (from User::die).  
  1426.  
  1427.   LocatorP locator = get_locator();
  1428.   assert(held);
  1429.   assert(locator->lookup(holderId) == dropper);
  1430.  
  1431.   held = False; 
  1432.   const Area area = dropper->get_area();
  1433.  
  1434.   Pos middleNext = area.get_middle(); 
  1435.  
  1436.   // Decide whether to drop to side or below.
  1437.   if (dropper->is_creature())
  1438.     {
  1439.       Touching touching = ((CreatureP)dropper)->get_touching_area();
  1440.       if (touching == CO_dn)
  1441.     {
  1442.       switch(dropper->get_dir()) {
  1443.       case CO_center_R:
  1444.       case CO_dn_R:
  1445.         middleNext.x -= ITEM_DROP_OFFSET_WIDTH;
  1446.         break;
  1447.       case CO_center_L:
  1448.       case CO_dn_L:
  1449.         middleNext.x += ITEM_DROP_OFFSET_WIDTH;
  1450.         break;
  1451.       default:
  1452.         middleNext.x += (Utils::coinFlip() ? ITEM_DROP_OFFSET_WIDTH : 
  1453.                  - ITEM_DROP_OFFSET_WIDTH);
  1454.       };
  1455.     }
  1456.       else
  1457.     middleNext.y += ITEM_DROP_OFFSET_HEIGHT;
  1458.     }
  1459.   else
  1460.     middleNext.x += 
  1461.       (Utils::coinFlip() ? ITEM_DROP_OFFSET_WIDTH : - ITEM_DROP_OFFSET_WIDTH);
  1462.  
  1463.   set_middle_next(middleNext);
  1464.   canTake.set();
  1465.   set_mapped_next(True);
  1466. }
  1467.  
  1468.  
  1469.  
  1470. void Item::use(PhysicalP)
  1471. {
  1472.   dieMessage = USED;
  1473. }
  1474.  
  1475.  
  1476.  
  1477. void Item::act()
  1478. {
  1479.   canTake.clock();
  1480.   Falling::act();
  1481. }
  1482.  
  1483.  
  1484.  
  1485. void Item::die()
  1486. {
  1487.   LocatorP locator = get_locator();
  1488.   ostrstream msg;
  1489.   switch (dieMessage) {
  1490.   case NONE:
  1491.     break;
  1492.   case USED:
  1493.     msg << identify() << " has been used." << ends;
  1494.     locator->message_enq(msg.str());
  1495.     break;
  1496.   case DESTROYED:
  1497.     msg << identify() << " is destroyed." << ends;
  1498.     locator->message_enq(msg.str());
  1499.     break;
  1500.   };
  1501.  
  1502.  Falling::die();
  1503. }
  1504.  
  1505.  
  1506.  
  1507. AutoUse::AutoUse(const AutoUseContext &c,
  1508.          AutoUseXdata &x_data,
  1509.          WorldP w,
  1510.          LocatorP l,
  1511.          const Pos &pos) :
  1512. Item(c.itemContext,x_data,w,l,pos) 
  1513. {}
  1514.  
  1515.  
  1516.  
  1517. void AutoUse::collide(PhysicalP other)
  1518. {
  1519.   if (!other->is_creature() || other->is_user() || !other->get_intel())
  1520.     Item::collide(other);
  1521.   else
  1522.     use(other);
  1523. }
  1524.  
  1525.  
  1526.  
  1527. Shield::Shield(const ShieldContext &s_c,
  1528.            ShieldXdata &x_data,
  1529.            WorldP w,
  1530.            LocatorP l,
  1531.            const Pos &pos) 
  1532. : AutoUse(s_c.autoUseContext,x_data,w,l,pos) 
  1533. {}
  1534.  
  1535.  
  1536.  
  1537. Boolean Shield::is_shield()
  1538. {
  1539.   return True;
  1540. }
  1541.  
  1542.  
  1543.  
  1544. void Shield::use(PhysicalP p)
  1545. {
  1546.   stats.add_use();
  1547.   assert(p->is_moving());
  1548.  
  1549.   LocatorP l = get_locator();
  1550.   Id id = ((MovingP)p)->get_protection();
  1551.   ProtectionP oldProtection = (ProtectionP) l->lookup(id);
  1552.   if (oldProtection)
  1553.     oldProtection->kill_self();
  1554.  
  1555.   ProtectionP protection = create_protection(p->get_area());
  1556.   LocatorP locator = get_locator();
  1557.   locator->add(protection);
  1558.   ((MovingP)p)->set_protection(protection->get_id());
  1559.  
  1560.   kill_self();
  1561.   AutoUse::use(p);
  1562. }
  1563.  
  1564.  
  1565.  
  1566. Stats Shield::stats;
  1567.  
  1568.  
  1569.  
  1570. Animated::Animated(const AnimatedContext &a_c,
  1571.            AnimatedXdata &x_data,
  1572.            WorldP w,
  1573.            LocatorP l,
  1574.            const Pos &pos) :
  1575.        Item(a_c.itemContext,x_data.itemXdata,w,l,pos) 
  1576. {
  1577.   animatedXdata = &x_data;
  1578.   ac = &a_c;
  1579.   frame = frameNext = 0;
  1580.   animatedAnimNum = Utils::choose(ac->animMax[frame]);
  1581.  
  1582.   assert(context_valid());
  1583. }
  1584.  
  1585.  
  1586.  
  1587. void Animated::get_pixmap_mask(int dpyNum,Pixmap &pixmap,Pixmap &mask,Dir,int)
  1588. {
  1589.   pixmap = animatedXdata->pixmaps[dpyNum][frame][animatedAnimNum];
  1590.   mask = animatedXdata->masks[dpyNum][frame][animatedAnimNum];
  1591. }
  1592.  
  1593.  
  1594.  
  1595. void Animated::get_size_offset_next(Size &size,Size &offset,Dir)
  1596. {
  1597.   size = ac->size;
  1598.   offset.width = offset.height = 0;
  1599. }
  1600.  
  1601.  
  1602.  
  1603. void Animated::init_x(Xvars &xvars) 
  1604. {
  1605.   assert(animatedXdata->valid == False);
  1606.  
  1607.   for (int dpyNum = 0; dpyNum < xvars.dpyMax; dpyNum++)
  1608.     for (int f = 0; f < PH_FRAME_MAX; f++)
  1609.       for (int n = 0; n < ac->animMax[f]; n++)
  1610.     {
  1611.       animatedXdata->pixmaps[dpyNum][f][n] = 
  1612.         XCreatePixmapFromBitmapData(xvars.dpy[dpyNum],xvars.root[dpyNum],
  1613.                     ac->pixmapBits[f][n],
  1614.                     ac->size.width,ac->size.height,
  1615.                     xvars.black[dpyNum],
  1616.                     xvars.allocNamedColor(dpyNum,
  1617.                                   ac->colorName),
  1618.                     xvars.depth[dpyNum]);
  1619.       animatedXdata->masks[dpyNum][f][n] = 
  1620.         XCreateBitmapFromData(xvars.dpy[dpyNum],xvars.root[dpyNum],
  1621.                   ac->maskBits[f][n],
  1622.                   ac->size.width,ac->size.height);
  1623.       }
  1624.   animatedXdata->valid = True;
  1625.   
  1626.   Item::init_x(xvars);
  1627. }
  1628.  
  1629.  
  1630.  
  1631. void Animated::update()
  1632. {
  1633.   animatedAnimNum = (animatedAnimNum + 1) % ac->animMax[frame];
  1634.   
  1635.   if (frame != frameNext)
  1636.     animatedAnimNum = 0;
  1637.   frame = frameNext;
  1638.  
  1639.  Item::update();
  1640. }
  1641.  
  1642.  
  1643.  
  1644. Boolean Animated::context_valid()
  1645. {
  1646.   for (int f = 0; f < PH_FRAME_MAX; f++)
  1647.     {
  1648.       if (ac->animMax[f] < 0)
  1649.     return False;
  1650.       for (int m = 0; m < ac->animMax[f]; m++)
  1651.     if ((ac->pixmapBits[f][m] == 0) || (ac->maskBits[f][m] == 0))
  1652.       return False;
  1653.     }
  1654.  
  1655.   return True;
  1656. }
  1657.  
  1658.  
  1659.  
  1660. Weapon::Weapon(const WeaponContext &c_x,
  1661.            WeaponXdata &x_data,
  1662.            WorldP w,
  1663.            LocatorP l,
  1664.            const Pos &pos) 
  1665.      : Item(c_x.itemContext,x_data,w,l,pos) 
  1666. {
  1667.   enteredScope = False;
  1668.   wc = &c_x;
  1669. }
  1670.  
  1671.  
  1672.  
  1673. Boolean Weapon::ready()
  1674. {
  1675.   assert(0);
  1676.   return False;
  1677. }
  1678.  
  1679.  
  1680.  
  1681. void Weapon::fire(const Id &,ITcommand)
  1682. {}
  1683.  
  1684.  
  1685.  
  1686. void Weapon::enter_scope_next(PhysicalP)
  1687. {
  1688. /*  #ifdef PRINT_ERRORS
  1689.   if (enteredScope)
  1690.     cerr << "Warning:: " << identify() << " already entered scope." << endl;
  1691.     #endif */
  1692.   enteredScope = True;
  1693. }
  1694.  
  1695.  
  1696.  
  1697. void Weapon::leave_scope_next(PhysicalP)
  1698. {
  1699. /* #ifdef PRINT_ERRORS
  1700.   if (!enteredScope)
  1701.     cerr << "Warning:: " << identify() << " not in scope." << endl;
  1702.     #endif */
  1703.   enteredScope = False;
  1704. }
  1705.  
  1706.  
  1707.  
  1708. void Weapon::take_ammo_from(WeaponP other)
  1709. {
  1710.   int thisAmmo = get_ammo();
  1711.   int otherAmmo = other->get_ammo();
  1712.  
  1713.   if ((thisAmmo != PH_AMMO_UNLIMITED) && (otherAmmo != PH_AMMO_UNLIMITED))
  1714.     {
  1715.       int maxTake = get_ammo_max() - thisAmmo;
  1716.       int trans = min(maxTake,otherAmmo);
  1717.       
  1718.       set_ammo(thisAmmo + trans);
  1719.       other->set_ammo(otherAmmo - trans);
  1720.     }
  1721. }
  1722.  
  1723.  
  1724.  
  1725. Cutter::Cutter(const CutterContext &c_x,CutterXdata &x_data,
  1726.        WorldP w,LocatorP l,const Pos &pos)
  1727.      : Weapon(c_x.weaponContext,x_data.weaponXdata,w,l,pos)
  1728. {
  1729.   inScope = inScopeNext = False;
  1730.   context = &c_x;
  1731.   cutterXdata = &x_data;
  1732. }
  1733.  
  1734.  
  1735.  
  1736. Boolean Cutter::is_cutter()
  1737. {
  1738.   return True;
  1739. }
  1740.  
  1741.  
  1742.  
  1743. Boolean Cutter::ready()
  1744. {
  1745.   return False;
  1746. }
  1747.  
  1748.  
  1749.  
  1750. int Cutter::get_ammo()
  1751. {
  1752.   return PH_AMMO_UNLIMITED;
  1753. }
  1754.  
  1755.  
  1756.  
  1757. int Cutter::get_ammo_max()
  1758. {
  1759.   return PH_AMMO_UNLIMITED;
  1760. }
  1761.  
  1762.  
  1763.  
  1764. void Cutter::get_pixmap_mask(int dpyNum,Pixmap &pixmap,Pixmap &mask,
  1765.                  Dir dir,int animNum)
  1766. {
  1767.   if (!inScope)
  1768.     {
  1769.       pixmap = cutterXdata->unheldPixmap[dpyNum];
  1770.       mask = cutterXdata->unheldMask[dpyNum];
  1771.     }
  1772.   else
  1773.     Weapon::get_pixmap_mask(dpyNum,pixmap,mask,dir,animNum);
  1774. }
  1775.  
  1776.  
  1777.   
  1778. void Cutter::get_size_offset_next(Size &size,Size &offset,
  1779.                   Dir dirNext)
  1780. {
  1781.   if (!inScope)
  1782.     {
  1783.       size = context->unheldSize;
  1784.       offset = context->unheldSize;
  1785.     }
  1786.   else
  1787.     Weapon::get_size_offset_next(size,offset,dirNext);
  1788. }
  1789.  
  1790.  
  1791.                  
  1792. void Cutter::set_ammo(int)
  1793. {
  1794.   assert(0);
  1795. }
  1796.  
  1797.  
  1798.  
  1799. void Cutter::follow_user(const Pos &userMiddle,Dir userDir)
  1800. {
  1801.   if (inScope)
  1802.     {
  1803.       set_dir_next(userDir);
  1804.       set_middle_next(userMiddle + context->offsets[userDir]);
  1805.     }
  1806.   else
  1807.     set_middle_next(userMiddle);
  1808. }
  1809.  
  1810.  
  1811.  
  1812. void Cutter::enter_scope_next(PhysicalP user)
  1813. {
  1814.   if(!entered_scope())
  1815.     {
  1816.       set_dont_collide(user);
  1817.       set_mapped_next(True);
  1818.       killerId = user->get_id();
  1819.       set_dir_next(CO_center);
  1820.       inScopeNext = True;
  1821.       
  1822.       Weapon::enter_scope_next(user);
  1823.     }
  1824. #ifdef PRINT_ERRORS
  1825.   else
  1826.     cerr << "Warning:: " << identify() << " entered scope twice." << endl;
  1827. #endif
  1828. }
  1829.  
  1830.  
  1831.  
  1832. void Cutter::leave_scope_next(PhysicalP user)
  1833. {
  1834.   if (entered_scope())
  1835.     {
  1836.       set_dont_collide(NULL);
  1837.       set_mapped_next(False);
  1838.       set_dir_next(CO_air);
  1839.       inScopeNext = False;
  1840.       
  1841.       Weapon::leave_scope_next(user);
  1842.     }
  1843. #ifdef PRINT_ERRORS
  1844.   else
  1845.     cerr << "Warning:: " << identify() << " left scope twice." << endl;
  1846. #endif
  1847. }
  1848.  
  1849.  
  1850.  
  1851. void Cutter::collide(PhysicalP other)
  1852. {
  1853.   if (inScope)
  1854.     {
  1855.       PhysicalP p;
  1856.       LocatorP locator = get_locator();
  1857.       if (locator->lookup(p,killerId) == OL_NO_SIG)
  1858.     other->corporeal_attack(p,context->damage);
  1859.       else
  1860.     other->corporeal_attack(NULL,context->damage);
  1861.     }
  1862.   else
  1863.     Weapon::collide(other);
  1864. }
  1865.  
  1866.  
  1867.  
  1868. void Cutter::init_x(Xvars &xvars)
  1869. {
  1870.   assert(cutterXdata->valid == False);
  1871.  
  1872.   for (int dpyNum = 0; dpyNum < xvars.dpyMax; dpyNum++)
  1873.     {
  1874.       cutterXdata->unheldPixmap[dpyNum] = 
  1875.     XCreatePixmapFromBitmapData(xvars.dpy[dpyNum],xvars.root[dpyNum],
  1876.                     context->unheldPixmapBits,
  1877.                     context->unheldSize.width,
  1878.                     context->unheldSize.height,
  1879.                     xvars.black[dpyNum],
  1880.                     xvars.allocNamedColor(dpyNum,
  1881.                               context->unheldColorName),
  1882.                     xvars.depth[dpyNum]);
  1883.       cutterXdata->unheldMask[dpyNum] = 
  1884.     XCreateBitmapFromData(xvars.dpy[dpyNum],xvars.root[dpyNum],
  1885.                   context->unheldMaskBits,
  1886.                   context->unheldSize.width,
  1887.                   context->unheldSize.height);
  1888.   
  1889.       cutterXdata->valid = True;
  1890.     }
  1891.   Weapon::init_x(xvars);
  1892. }
  1893.  
  1894.  
  1895.  
  1896. void Cutter::update()
  1897. {
  1898.   inScope = inScopeNext;
  1899.   Weapon::update();
  1900. }
  1901.  
  1902.  
  1903.  
  1904. Creature::Creature(const CreatureContext &c_c,
  1905.            CreatureXdata &x_data,
  1906.            WorldP w,           
  1907.            LocatorP l,
  1908.            const Pos &raw_pos)
  1909.      : Moving(c_c.movingContext,x_data.movingXdata,w,l,raw_pos)
  1910. {
  1911.   touching = CO_air;
  1912.   canClimb = False;
  1913.   stance = stanceNext = CO_air;
  1914.   grav = gravNext = 0;
  1915.   cc = &c_c;
  1916.   Timer nTimer(CORPSE_TIME);
  1917.   corpseTimer = nTimer;
  1918.   assert(context_valid());
  1919.   creatureXdata = &x_data;
  1920.   birthTime = time(NULL);
  1921. }
  1922.  
  1923.  
  1924.  
  1925. Creature::Creature()
  1926. {
  1927.   assert(0);
  1928. }
  1929.  
  1930.  
  1931.  
  1932. Boolean Creature::is_creature()
  1933. {
  1934.   return True;
  1935. }
  1936.  
  1937.  
  1938.  
  1939. void Creature::set_quiet_death()
  1940. {
  1941.   // Get rid of corpses.
  1942.   if (!alive())
  1943.     set_delete_me();
  1944.  
  1945.   Moving::set_quiet_death();
  1946. }
  1947.  
  1948.  
  1949.  
  1950. void Creature::corporeal_attack(PhysicalP killer,int damage) 
  1951. {
  1952.   // Does not take the possible existence of a Protection into account for
  1953.   // figuring out killer.
  1954.  
  1955.   IntelP kIntel;
  1956.   IntelId kIntelId; // Starts out invalid.
  1957.   if (killer && (kIntel = killer->get_intel()))
  1958.     kIntelId = kIntel->get_intel_id();
  1959.   
  1960.   IntelP intel = get_intel();
  1961.   if (intel)
  1962.     intel->set_killer_intel_id(kIntelId);
  1963.   
  1964.   Moving::corporeal_attack(killer,damage);
  1965. }
  1966.  
  1967.  
  1968.  
  1969. void Creature::heat_attack(PhysicalP killer,int heat,Boolean secondary)
  1970. {
  1971.   // Does not take the possible existence of a Protection into account for
  1972.   // figuring out killer.
  1973.  
  1974.   IntelP kIntel;
  1975.   IntelId kIntelId; // Starts out invalid.
  1976.   if (killer && (kIntel = killer->get_intel()))
  1977.     kIntelId = kIntel->get_intel_id();
  1978.   
  1979.   IntelP intel = get_intel();
  1980.   if (intel)
  1981.     intel->set_killer_intel_id(kIntelId);
  1982.  
  1983.   Moving::heat_attack(killer,heat,secondary);
  1984. }
  1985.  
  1986.  
  1987.  
  1988. void Creature::act()
  1989. {
  1990.   Vel velNext = get_vel_next();
  1991.   // Account for gravity.
  1992.   velNext.dy += gravNext; 
  1993.   
  1994.   switch (stanceNext) {
  1995.   case CO_air:
  1996.     velNext.limit(cc->airSpeed);
  1997.     break;
  1998.   case CO_center:
  1999.     velNext.limit(cc->centerSpeed);
  2000.     break;
  2001.   case CO_climb:
  2002.     velNext.limit(cc->climbSpeed);
  2003.     break;
  2004.   default:
  2005.     velNext.limit(cc->crawlSpeed);
  2006.     break;
  2007.   }    
  2008.   set_vel_next(velNext);
  2009.   set_dir_next(compute_dir(stanceNext,velNext));
  2010.  
  2011.   if (! alive())
  2012.     {
  2013.       if (get_intel())
  2014.     cerr << "Warning: Creature::act(): Corpse with non-NULL intelligence."
  2015.       << endl;
  2016.       corpseTimer.clock();
  2017.     }
  2018.  
  2019.  Moving::act();
  2020. }
  2021.  
  2022.  
  2023.  
  2024. void Creature::update()
  2025. {
  2026.   stance = stanceNext;
  2027.   grav = gravNext;
  2028.   const Area area = get_area_next();
  2029.   
  2030.   WorldP world = get_world();
  2031.   world->touchingHanging(touching,hanging,area);
  2032.   canClimb = world->canClimb(area.middle_wsquare());
  2033.  
  2034.   // Remove corpse after time limit or if damaged enough.
  2035.   if (!get_quiet_death() && !alive() && 
  2036.       (corpseTimer.ready() || (get_health() < - cc->corpseHealth)))
  2037.     {
  2038.       LocatorP locator = get_locator();
  2039.       ostrstream msg;
  2040.       if (corpseTimer.ready())
  2041.     {
  2042.       msg << identify() << " corpse has decomposed." << ends;
  2043.       locator->message_enq(msg.str());
  2044.     }
  2045.       else
  2046.     {
  2047.       msg << identify() << " corpse has been destroyed." << ends;
  2048.       locator->message_enq(msg.str());
  2049.     }
  2050.       set_delete_me();
  2051.     }
  2052.  
  2053.   Moving::update();
  2054. }
  2055.  
  2056.  
  2057.  
  2058. void Creature::die()
  2059. {
  2060.   if (!get_quiet_death())
  2061.     stats.add_death(birthTime);
  2062.  
  2063.   // Prepare for being a corpse.
  2064.   LocatorP locator = get_locator();
  2065.   if (!get_quiet_death())
  2066.     {    
  2067.       corpseTimer.set();
  2068.       
  2069.       // Set current and next values because called in update phase.
  2070.       Vel velNew(0,DROP_SPEED);
  2071.       set_vel_next(velNew);
  2072.       set_stance_next(CO_air);
  2073.       
  2074.       ostrstream msg;
  2075.       msg << identify() << " has died." << ends;
  2076.       locator->message_enq(msg.str());
  2077.  
  2078.       set_no_death_delete();
  2079.     }
  2080.  
  2081.  
  2082.   // Deal with awarding kills.
  2083.   IntelP intel = get_intel();
  2084.   IntelId killerIntelId;
  2085.   if (intel)
  2086.     killerIntelId = intel->get_killer_intel_id();
  2087.   IntelP killerIntel;
  2088.   if (killerIntel = locator->lookup(killerIntelId))
  2089.     {
  2090.       // Compute soups.  I.e. A human killed by something other than a 
  2091.       // different human.
  2092.       if (intel && intel->is_human() && 
  2093.       (!killerIntel || !killerIntel->is_human() || killerIntel == intel))
  2094.     intel->add_soup();
  2095.  
  2096.       // Award killer with a kill of the appropriate type.  Don't get kills
  2097.       // for taking yourself out.
  2098.       if (intel && killerIntel && intel != killerIntel)
  2099.     {
  2100.       if (intel->is_human())
  2101.         killerIntel->add_human_kill();
  2102.       else if (((MachineP)intel)->is_enemy())
  2103.         killerIntel->add_enemy_kill();
  2104.     }
  2105.     }
  2106.   else if (intel && intel->is_human())
  2107.     intel->add_soup();
  2108.   
  2109.   Moving::die();
  2110. }
  2111.  
  2112.  
  2113.  
  2114. Touching Creature::get_touching_stance()
  2115. {
  2116.   if (stance == CO_center)
  2117.     return  CO_dn;
  2118.   else if (stance == CO_climb)
  2119.     return  CO_air;
  2120.   else
  2121.     return (Touching)stance;
  2122. }
  2123.  
  2124.  
  2125.  
  2126. void Creature::center_wsquare_x_next(const Loc &loc)
  2127. {
  2128.   const Area area = get_area();
  2129.   const MovingContext *cc = get_moving_context();
  2130.   const Pos rawPos = get_raw_pos();
  2131.   assert (stanceNext == CO_climb);
  2132.   assert (area.overlap(loc));
  2133.  
  2134.   Pos rpos(loc.c * WSQUARE_WIDTH + 
  2135.        (WSQUARE_WIDTH - cc->sizes[CO_climb].width) / 2 -
  2136.        cc->offsets[CO_climb].width,
  2137.        rawPos.y);
  2138.  
  2139.   set_raw_pos_next(rpos);
  2140. }
  2141.  
  2142.  
  2143.  
  2144. void Creature::corner(const Hanging &hanging)
  2145. {
  2146.   Pos rpos;
  2147.   const Loc loc = hanging.loc;
  2148.   const MovingContext *mc = get_moving_context();
  2149.  
  2150.  
  2151.   switch (hanging.corner) {
  2152.   case CO_up_L:  // Final is CO_r_DN.
  2153.     assert(stanceNext == CO_r);
  2154.     rpos.x = loc.c * WSQUARE_WIDTH - mc->sizes[CO_r].width - 
  2155.       mc->offsets[CO_r].width;
  2156.     rpos.y = (loc.r + 1) * WSQUARE_HEIGHT - 
  2157.       (int)ceil(0.5 * mc->sizes[CO_r].height) - mc->offsets[CO_r].height;
  2158.     break;
  2159.  
  2160.   case CO_dn_L:  // Final is CO_r_UP.
  2161.     assert(stanceNext == CO_r);
  2162.     rpos.x = loc.c * WSQUARE_WIDTH - mc->sizes[CO_r].width - 
  2163.       mc->offsets[CO_r].width;
  2164.     rpos.y = loc.r * WSQUARE_HEIGHT - (int)floor(0.5 * mc->sizes[CO_r].height) -
  2165.       mc->offsets[CO_r].height;
  2166.     break;
  2167.     
  2168.   case CO_l_UP:  // Final is CO_dn_R.
  2169.     assert(stanceNext == CO_dn);
  2170.     rpos.x = (loc.c + 1) * WSQUARE_WIDTH - 
  2171.       (int)ceil(0.5 * mc->sizes[CO_dn].width) - mc->offsets[CO_dn].width;
  2172.     rpos.y = loc.r * WSQUARE_HEIGHT - mc->sizes[CO_dn].height - 
  2173.       mc->offsets[CO_dn].height;
  2174.     break;
  2175.  
  2176.   case CO_r_UP:  // Final is CO_dn_L.
  2177.     assert(stanceNext == CO_dn);
  2178.     rpos.x = loc.c * WSQUARE_WIDTH - (int)floor(0.5 * mc->sizes[CO_dn].width) -
  2179.       mc->offsets[CO_dn].width;
  2180.     rpos.y = loc.r * WSQUARE_HEIGHT - mc->sizes[CO_dn].height - 
  2181.       mc->offsets[CO_dn].height;
  2182.     break;
  2183.  
  2184.   case CO_up_R:  // Final is CO_l_DN.
  2185.     assert(stanceNext == CO_l);
  2186.     rpos.x = (loc.c + 1) * WSQUARE_WIDTH - mc->offsets[CO_l].width;
  2187.     rpos.y = (loc.r + 1) * WSQUARE_HEIGHT - 
  2188.       (int)ceil(0.5 * mc->sizes[CO_l].height) - mc->offsets[CO_l].height;
  2189.     break;
  2190.  
  2191.   case CO_dn_R:  // Final is CO_l_UP.
  2192.     assert(stanceNext == CO_l);
  2193.     rpos.x = (loc.c + 1) * WSQUARE_WIDTH - mc->offsets[CO_l].width;
  2194.     rpos.y = loc.r * WSQUARE_HEIGHT - 
  2195.       (int)floor(0.5 * mc->sizes[CO_l].height) - mc->offsets[CO_l].height;
  2196.     break;
  2197.  
  2198.   case CO_l_DN:  // Final is CO_up_R.
  2199.     assert(stanceNext == CO_up);
  2200.     rpos.x = (loc.c + 1) * WSQUARE_WIDTH - 
  2201.       (int)ceil(0.5 * mc->sizes[CO_up].width) - mc->offsets[CO_up].width;
  2202.     rpos.y = (loc.r + 1) * WSQUARE_HEIGHT - mc->offsets[CO_up].height;
  2203.     break;
  2204.  
  2205.   case CO_r_DN:  // Final is CO_up_L.
  2206.     assert(stanceNext == CO_up);
  2207.     rpos.x = loc.c * WSQUARE_WIDTH - (int)floor(0.5 * mc->sizes[CO_up].width) -
  2208.       mc->offsets[CO_up].width;
  2209.     rpos.y = (loc.r + 1) * WSQUARE_HEIGHT - mc->offsets[CO_up].height;
  2210.     break;
  2211.  
  2212.   default:
  2213.     assert(0);
  2214.   }
  2215.   
  2216.   set_raw_pos_next(rpos);
  2217. }
  2218.  
  2219.  
  2220.  
  2221. void Creature::get_pixmap_mask(int dpyNum,Pixmap &pixmap,Pixmap &mask,
  2222.                    Dir dir,int animNum)
  2223. {
  2224.   if (! alive())
  2225.     {
  2226.       pixmap = creatureXdata->deadPixmap[dpyNum];
  2227.       mask = creatureXdata->deadMask[dpyNum];
  2228.     }
  2229.   else
  2230.     Moving::get_pixmap_mask(dpyNum,pixmap,mask,dir,animNum);
  2231. }
  2232.  
  2233.  
  2234.  
  2235. void Creature::get_size_offset_next(Size &size,Size &offset,Dir dir)
  2236. {
  2237.   if (! alive_next())
  2238.     {
  2239.       size = cc->deadSize;
  2240.       offset = cc->deadOffset;
  2241.     }
  2242.   else
  2243.     Moving::get_size_offset_next(size,offset,dir);
  2244. }
  2245.  
  2246.  
  2247.  
  2248. void Creature::set_stance_next(const Stance &stance)
  2249. {
  2250.   assert((stance == CO_r) || (stance == CO_dn) || (stance == CO_l) ||
  2251.      (stance == CO_up) || (stance == CO_air) || 
  2252.      (stance == CO_center) || (stance == CO_climb)); 
  2253.   stanceNext = stance; 
  2254. }
  2255.  
  2256.  
  2257.  
  2258. void Creature::init_x(Xvars &xvars)
  2259. {
  2260.   assert(creatureXdata->valid == False);
  2261.  
  2262.   const MovingContext *mc = get_moving_context();
  2263.  
  2264.   for (int dpyNum = 0; dpyNum < xvars.dpyMax; dpyNum++)
  2265.     {
  2266.       creatureXdata->deadPixmap[dpyNum] =      
  2267.     XCreatePixmapFromBitmapData(xvars.dpy[dpyNum],xvars.root[dpyNum],
  2268.                     cc->deadPixmapBits,
  2269.                     cc->deadSize.width,cc->deadSize.height,
  2270.                     xvars.allocNamedColor(dpyNum,
  2271.                               mc->foreColorName,
  2272.            mc->foreWhiteDefault ? xvars.white[dpyNum] : xvars.black[dpyNum]),
  2273.                     xvars.allocNamedColor(dpyNum,
  2274.                               mc->backColorName,
  2275.        mc->backWhiteDefault ? xvars.white[dpyNum] : xvars.black[dpyNum]),
  2276.                     xvars.depth[dpyNum]);
  2277.       creatureXdata->deadMask[dpyNum] = 
  2278.     XCreateBitmapFromData(xvars.dpy[dpyNum],xvars.root[dpyNum],
  2279.                   cc->deadMaskBits,
  2280.                   cc->deadSize.width,cc->deadSize.height);
  2281.     }
  2282.  
  2283.   creatureXdata->valid = True;
  2284.   Moving::init_x(xvars);
  2285. }
  2286.  
  2287.  
  2288.  
  2289. Dir Creature::compute_dir(const Stance &st,const Vel &v)
  2290. {
  2291.   Dir ret = CO_center;
  2292.   
  2293.   switch (st) {
  2294.   case CO_r:
  2295.     if (fabs(v.dy) < VEL_SMALL)
  2296.       ret = CO_r;
  2297.     else
  2298.       ret = v.dy > 0 ? CO_r_DN : CO_r_UP;
  2299.     break;
  2300.     
  2301.   case CO_dn:
  2302.     if (fabs(v.dx) < VEL_SMALL)
  2303.       ret = CO_dn;
  2304.     else
  2305.       ret = v.dx > 0 ? CO_dn_R : CO_dn_L;
  2306.     break;
  2307.  
  2308.   case CO_l:
  2309.     if (fabs(v.dy) < VEL_SMALL)
  2310.       ret = CO_l;
  2311.     else
  2312.       ret = v.dy > 0 ? CO_l_DN : CO_l_UP;
  2313.     break;
  2314.     
  2315.   case CO_up:
  2316.     if (fabs(v.dx) < VEL_SMALL)
  2317.       ret = CO_up;
  2318.     else
  2319.       ret = v.dx > 0 ? CO_up_R : CO_up_L;
  2320.     break;
  2321.  
  2322.   case CO_center:
  2323.     if (fabs(v.dx) < VEL_SMALL)
  2324.       ret = CO_center;
  2325.     else
  2326.       ret = v.dx > 0 ? CO_center_R : CO_center_L;
  2327.     break;
  2328.  
  2329.   // If diagonal, will give horizontal direction.
  2330.   case CO_air:
  2331.     if (fabs(v.dx) < VEL_SMALL)
  2332.       {
  2333.     if (fabs(v.dy) < VEL_SMALL)
  2334.       ret = CO_air;
  2335.     else
  2336.       // Changed
  2337.       ret = v.dy > 0 ? CO_air_DN : CO_air_UP;
  2338.       }
  2339.     else
  2340.       ret = v.dx > 0 ? CO_air_R : CO_air_L;
  2341.     break;
  2342.  
  2343.   // If diagonal, will give horizontal direction.
  2344.   case CO_climb:
  2345.     if (fabs(v.dx) < VEL_SMALL)
  2346.       {
  2347.     if (fabs(v.dy) < VEL_SMALL)
  2348.       ret = CO_climb;
  2349.     else
  2350.       // Changed
  2351.       ret = v.dy > 0 ? CO_climb_DN : CO_climb_UP;
  2352.       }
  2353.     else
  2354.       ret = v.dx > 0 ? CO_climb_R : CO_climb_L;
  2355.     break;
  2356.     
  2357.   default:
  2358.     assert (0);
  2359.     break;
  2360.   }
  2361.  
  2362.   return ret;
  2363. }
  2364.  
  2365.  
  2366.  
  2367. Boolean Creature::context_valid()
  2368. {
  2369.   if ((cc->crawlSpeed < 0) || (cc->centerSpeed < 0) || (cc->airSpeed < 0) || 
  2370.       (cc->climbSpeed < 0) || (cc->jump < 0) || (cc->acceleration < 0))
  2371.     return False;
  2372.   
  2373.   return True;
  2374. }
  2375.  
  2376.  
  2377.  
  2378. Stats Creature::stats;
  2379.  
  2380.  
  2381.  
  2382. Grounded::Grounded(const GroundedContext &,GroundedXdata &)
  2383. {}
  2384.  
  2385.  
  2386.  
  2387. void Grounded::act()
  2388. {
  2389.   _act();
  2390.   Creature::act();
  2391. }
  2392.  
  2393.  
  2394.  
  2395. void Grounded::_act()
  2396. {
  2397.   // Methods of Moving or Creature.
  2398.   const CreatureContext *cc = get_creature_context();
  2399.   const Stance stance = get_stance();
  2400.   const Touching touchingArea = get_touching_area();
  2401.   const Touching touchingStance = get_touching_stance();
  2402.   const Vel vel = get_vel();
  2403.   const Acc *unitAccs = get_unit_accs();
  2404.   const ITcommand command = get_command(); 
  2405.   
  2406.   
  2407.   if (touchingArea != touchingStance)
  2408.     {
  2409.       // Hit the ground.
  2410.       if (touchingArea == CO_dn) 
  2411.     {
  2412.       set_stance_next(CO_center);
  2413.       Vel velNew(vel.dx,0);
  2414.       set_vel_next(velNew);
  2415.     }
  2416.       // Hit side walls.
  2417.       else if ((touchingArea == CO_r) || (touchingArea == CO_l))
  2418.     {
  2419.       Vel velNew(0,vel.dy);
  2420.       set_vel_next(velNew);
  2421.     }
  2422.       // In the air.
  2423.       else if (touchingArea == CO_air)
  2424.     set_stance_next(CO_air);
  2425.     }
  2426.   else if (touchingArea == CO_dn) 
  2427.     {
  2428.       Vel velNew(vel.dx,0);
  2429.       set_vel_next(velNew);
  2430.     }
  2431.   
  2432.   // Set gravity.
  2433.   set_grav_next((touchingArea == CO_dn) ? 0 : GRAVITY);
  2434.   
  2435.   /* Interpret commands from controlling intelligence.  May override some of 
  2436.      above settings. */
  2437.   switch (command) {
  2438.   case IT_CENTER:
  2439.     if (stance == CO_center)
  2440.       set_vel_next(0);
  2441.     break;
  2442.     
  2443.   case IT_R:
  2444.     if (stance == CO_center)
  2445.       set_vel_next(vel + cc->acceleration * unitAccs[CO_center_R]);
  2446.     break;
  2447.     
  2448.   case IT_L:
  2449.     if (stance == CO_center)
  2450.       set_vel_next(vel + cc->acceleration * unitAccs[CO_center_L]);
  2451.     
  2452.     break;
  2453.   };    
  2454. }
  2455.  
  2456.  
  2457.  
  2458. Suicide::Suicide(const SuicideContext &,SuicideXdata &)
  2459. {}
  2460.  
  2461.  
  2462.  
  2463. Boolean Suicide::is_suicide()
  2464. {
  2465.   return True;
  2466. }
  2467.  
  2468.  
  2469.  
  2470. void Suicide::act()
  2471. {
  2472.   _act();
  2473.   Creature::act();
  2474. }
  2475.  
  2476.  
  2477.  
  2478. void Suicide::_act()
  2479. {
  2480.   if (get_command() == IT_ITEM_USE)
  2481.     kill_self();
  2482. }
  2483.  
  2484.  
  2485.  
  2486. Hopping::Hopping(const HoppingContext &,HoppingXdata &)
  2487. {}
  2488.      
  2489.      
  2490.  
  2491. void Hopping::act()
  2492. {
  2493.   // Methods of Moving or Creature.
  2494.   const CreatureContext *cc = get_creature_context();
  2495.   const Stance stance = get_stance();
  2496.   const Touching touchingArea = get_touching_area();
  2497.   const Touching touchingStance = get_touching_stance();
  2498.   const Vel vel = get_vel();
  2499.   const Vel *unitVels = get_unit_vels();
  2500.   const Boolean canClimb = can_climb();
  2501.   const Area area = get_area();
  2502.   const ITcommand command = get_command(); 
  2503.   
  2504.   
  2505.   // Default set gravity.
  2506.   set_grav_next((touchingArea == CO_dn) || 
  2507.         (canClimb && (stance == CO_climb) && alive()) ? 0 : GRAVITY);
  2508.  
  2509.   
  2510.   // Change stance if necessary.
  2511.   if (stance != CO_climb) 
  2512.     {
  2513.       if (touchingArea != touchingStance)
  2514.     {
  2515.       // Hit the ground.
  2516.       if (touchingArea == CO_dn) 
  2517.         {
  2518.           set_stance_next(CO_center);
  2519.           set_vel_next(0);
  2520.         }
  2521.       // Side walls.
  2522.       else if (touchingArea == CO_r)
  2523.         {
  2524.           Vel velNew(0,vel.dy);
  2525.           set_vel_next(velNew);
  2526.         }
  2527.       else if (touchingArea == CO_l)
  2528.         {
  2529.           Vel velNew(0,vel.dy);
  2530.           set_vel_next(velNew);
  2531.         }
  2532.       else if (touchingArea == CO_air)
  2533.         set_stance_next(CO_air);
  2534.       else if (touchingArea != CO_up)
  2535.         assert(0);
  2536.     }
  2537.       else if (touchingArea == CO_dn) 
  2538.     {
  2539.       Vel velNew(vel.dx,0);
  2540.       set_vel_next(velNew);
  2541.     }
  2542.     }
  2543.   else // stance == CO_climb
  2544.     {
  2545.       // Stop climbing if not in climbing square. 
  2546.       if (!canClimb)  
  2547.     set_stance_next(CO_air);
  2548.       else if (! vel.is_zero())
  2549.     set_vel_next(0);
  2550.     }
  2551.   
  2552.  
  2553.   /* Interpret commands from controlling intelligence.  May override some of 
  2554.      above settings. */
  2555.   switch (command) {
  2556.   case IT_CENTER:
  2557.     if ((stance != CO_climb) && canClimb)
  2558.       {
  2559.     set_stance_next(CO_climb);
  2560.     set_grav_next(0);
  2561.     set_vel_next(0);
  2562.     center_wsquare_x_next(area.middle_wsquare());
  2563.       }
  2564.     break;
  2565.     
  2566.   case IT_R:
  2567.     if ((stance == CO_center) || (stance == CO_climb))
  2568.       {
  2569.     set_vel_next(cc->jump * unitVels[CO_UP_R_R]);
  2570.     set_stance_next(CO_air);
  2571.       }
  2572.     break;
  2573.     
  2574.   case IT_DN_R:
  2575.     if (stance == CO_climb)
  2576.       {
  2577.     set_vel_next(cc->jump * unitVels[CO_DN_R]);
  2578.     set_stance_next(CO_air);
  2579.       }
  2580.     break;
  2581.     
  2582.   case IT_DN:
  2583.     if ((stance != CO_climb) && canClimb)
  2584.       {
  2585.     set_stance_next(CO_climb);
  2586.     set_grav_next(0);
  2587.     set_vel_next(0);
  2588.     center_wsquare_x_next(area.middle_wsquare());
  2589.       }
  2590.     else if (stance == CO_climb)
  2591.       set_vel_next(cc->jump * unitVels[CO_climb_DN]);
  2592.     break;
  2593.     
  2594.   case IT_DN_L:
  2595.     if (stance == CO_climb) 
  2596.       {
  2597.     set_vel_next(cc->jump * unitVels[CO_DN_L]);
  2598.     set_stance_next(CO_air);
  2599.       }
  2600.     break;
  2601.     
  2602.   case IT_L:
  2603.     if ((stance == CO_center) || (stance == CO_climb)) 
  2604.       {
  2605.     set_vel_next(cc->jump * unitVels[CO_UP_L_L]);
  2606.     set_stance_next(CO_air);
  2607.       }
  2608.     break;
  2609.     
  2610.   case IT_UP_L:
  2611.     if ((stance == CO_center) || (stance == CO_climb)) 
  2612.       {
  2613.     set_vel_next(cc->jump * unitVels[CO_air_L]);
  2614.     set_stance_next(CO_air);
  2615.       }
  2616.     break;
  2617.     
  2618.   case IT_UP:
  2619.     if ((stance != CO_climb) && canClimb)
  2620.       {
  2621.     set_stance_next(CO_climb);
  2622.     set_vel_next(0);
  2623.     set_grav_next(0);
  2624.     center_wsquare_x_next(area.middle_wsquare());
  2625.       }
  2626.     else if (stance == CO_center) // Jump up.
  2627.       {
  2628.     set_vel_next(cc->jump * unitVels[CO_air_UP]);
  2629.     set_stance_next(CO_air);
  2630.       }
  2631.     else if (stance == CO_climb)
  2632.       set_vel_next(cc->jump * unitVels[CO_climb_UP]);
  2633.     break;
  2634.     
  2635.   case IT_UP_R:
  2636.     // Jump right.
  2637.     if ((stance == CO_center) || (stance == CO_climb)) 
  2638.       {
  2639.     set_vel_next(cc->jump * unitVels[CO_air_R]);
  2640.     set_stance_next(CO_air);
  2641.       }
  2642.     break;
  2643.   };
  2644.  
  2645.  Creature::act();
  2646. }
  2647.  
  2648.  
  2649.  
  2650. User::User(const UserContext &,UserXdata &)
  2651. {
  2652.   weaponsNum = weaponCurrent = itemsNum = itemCurrent = 0; 
  2653. }
  2654.  
  2655.  
  2656.  
  2657. Boolean User::is_user()
  2658. {
  2659.   return True;
  2660. }
  2661.  
  2662.  
  2663.  
  2664. int User::get_weapons_num()
  2665. {
  2666.   return weaponsNum;
  2667. }
  2668.  
  2669.  
  2670.  
  2671. int User::get_items_num()
  2672. {
  2673.   return itemsNum;
  2674. }
  2675.  
  2676.  
  2677.  
  2678. PhysicalP User::get_weapon(int n)
  2679. {
  2680.   assert(n >= 0);
  2681.   if (n < weaponsNum)
  2682.     {
  2683.       LocatorP locator = get_locator();
  2684.       PhysicalP ret;
  2685.       if (ret = locator->lookup(weapons[n]))
  2686.     return ret;
  2687.       else
  2688.     return NULL;
  2689.     }
  2690.   else
  2691.     return NULL;
  2692. }
  2693.  
  2694.  
  2695.  
  2696. PhysicalP User::get_item(int n)
  2697. {
  2698.   assert(n >= 0);
  2699.   if (n < itemsNum)
  2700.     {
  2701.       LocatorP locator = get_locator();
  2702.       PhysicalP ret;
  2703.       if (ret = locator->lookup(items[n]))
  2704.     return ret;
  2705.       else
  2706.     return NULL;
  2707.     }
  2708.   else
  2709.     return NULL;
  2710. }
  2711.  
  2712.  
  2713.  
  2714. PhysicalP User::get_weapon_current()
  2715. {
  2716.   assert (weaponCurrent <= weaponsNum);
  2717.   if (weaponCurrent != weaponsNum)
  2718.     {
  2719.       LocatorP locator = get_locator();
  2720.       PhysicalP ret;
  2721.       if (ret = locator->lookup(weapons[weaponCurrent]))
  2722.     return ret;
  2723.       else
  2724.     return NULL;
  2725.     }
  2726.   else
  2727.     return NULL;
  2728. }
  2729.  
  2730.  
  2731.  
  2732. PhysicalP User::get_item_current()
  2733. {
  2734.   assert (itemCurrent <= itemsNum);
  2735.   if (itemCurrent != itemsNum)
  2736.     {
  2737.       PhysicalP ret;
  2738.  
  2739.       LocatorP locator = get_locator();
  2740.       if (ret = locator->lookup(items[itemCurrent]))
  2741.     return ret;
  2742.       else
  2743.     return NULL;
  2744.     }
  2745.   else
  2746.     return NULL;
  2747. }
  2748.  
  2749.  
  2750.  
  2751. void User::set_mapped_next(Boolean val)
  2752. {
  2753.   if (get_mapped_next() != val)
  2754.     {
  2755.       LocatorP locator = get_locator();
  2756.       PhysicalP weapon;
  2757.       if ((weaponCurrent != weaponsNum) && 
  2758.       (weapon = locator->lookup(weapons[weaponCurrent])))
  2759.     {
  2760.       if (val)
  2761.         ((WeaponP)weapon)->enter_scope_next(this);
  2762.       else
  2763.         ((WeaponP)weapon)->leave_scope_next(this);
  2764.     }
  2765.     }
  2766.  
  2767.   Creature::set_mapped_next(val);
  2768. }
  2769.  
  2770.  
  2771.  
  2772. void User::act() 
  2773. {
  2774.   Creature::act(); 
  2775.   _act();
  2776. }
  2777.  
  2778.  
  2779.  
  2780. void User::_act()
  2781. {
  2782.   assert(weaponCurrent <= weaponsNum);
  2783.   assert(itemCurrent <= itemsNum);
  2784.  
  2785.   LocatorP locator = get_locator();
  2786.   ITcommand command = get_command();
  2787.  
  2788.  
  2789.   // Fire weapon.  
  2790.   if (Intel::is_command_weapon(command))
  2791.     {
  2792.       if (weaponCurrent != weaponsNum)
  2793.     {
  2794.       PhysicalP p;
  2795.       if (p = locator->lookup(weapons[weaponCurrent]))
  2796.         ((WeaponP)p)->fire(get_id(),command);
  2797.     }
  2798.     }
  2799.   else
  2800.     switch (command) {
  2801.  
  2802.     // Change weapon.
  2803.     case IT_WEAPON_CHANGE:
  2804.       {
  2805.     PhysicalP weapon;
  2806.     if ((weaponCurrent != weaponsNum) && 
  2807.         (weapon = locator->lookup(weapons[weaponCurrent])))
  2808.       ((WeaponP)weapon)->leave_scope_next(this);
  2809.     
  2810.     weaponCurrent = (weaponCurrent + 1) % (weaponsNum + 1);
  2811.  
  2812.     if ((weaponCurrent != weaponsNum) && 
  2813.         (weapon = locator->lookup(weapons[weaponCurrent])))
  2814.       {
  2815.         ((WeaponP)weapon)->enter_scope_next(this);
  2816.         weapon->flash();
  2817.       }
  2818.       }
  2819.       break;
  2820.     
  2821.  
  2822.     // Drop weapon.
  2823.     case IT_WEAPON_DROP:
  2824.       if (weaponCurrent < weaponsNum)
  2825.     {
  2826.       // Clean up dead weapons elsewhere.
  2827.  
  2828.       PhysicalP weapon;
  2829.       if (weapon = locator->lookup(weapons[weaponCurrent]))
  2830.         {
  2831.           ((WeaponP)weapon)->leave_scope_next(this);
  2832.           ((ItemP)weapon)->dropped(this);
  2833.           weaponsNum--;
  2834.           weapons[weaponCurrent] = weapons[weaponsNum];
  2835.  
  2836.           // Some weapon or weaponCurrent == weaponsNum.
  2837.           weaponCurrent = 0;
  2838.           PhysicalP weapon;
  2839.           if ((weaponCurrent != weaponsNum) &&
  2840.           (weapon = locator->lookup(weapons[weaponCurrent])))
  2841.         ((WeaponP)weapon)->enter_scope_next(this);
  2842.         }
  2843.     }
  2844.       break;
  2845.  
  2846.  
  2847.     // Use item.
  2848.     case IT_ITEM_USE:
  2849.       if (itemCurrent != itemsNum)
  2850.     {
  2851.       PhysicalP p;
  2852.       if (locator->lookup(p,items[itemCurrent]) == OL_NO_SIG)
  2853.         ((ItemP)p)->use(this);
  2854.       }
  2855.       break;
  2856.  
  2857.  
  2858.     // Change item.
  2859.     case IT_ITEM_CHANGE:
  2860.       // Allow user to set no item.
  2861.       itemCurrent = (itemCurrent + 1) % (itemsNum + 1);
  2862.  
  2863.       if (itemCurrent != itemsNum)
  2864.     {
  2865.       PhysicalP p = locator->lookup(items[itemCurrent]);
  2866.       if (p)
  2867.         p->flash();
  2868.     }
  2869.       break;
  2870.  
  2871.  
  2872.     // Drop item.
  2873.     case IT_ITEM_DROP:
  2874.       if (itemCurrent < itemsNum)
  2875.     {
  2876.       PhysicalP item;
  2877.       if (item = locator->lookup(items[itemCurrent]))
  2878.         {
  2879.           ((ItemP)item)->dropped(this);
  2880.           itemsNum--;
  2881.           items[itemCurrent] = items[itemsNum];
  2882.           
  2883.           itemCurrent = 0;
  2884.         }
  2885.     }
  2886.       break;
  2887.     }
  2888.  
  2889.   assert(weaponCurrent <= weaponsNum);
  2890.   assert(itemCurrent <= itemsNum);
  2891.   
  2892.  
  2893.   /* Go through list of weapons and items, moving them along with the object
  2894.      or deleting them if they no longer exist or have no ammo. */
  2895.  
  2896.   const Area &areaNext = get_area_next();
  2897.   const Pos middleNext = areaNext.get_middle();
  2898.   Dir dirNext = get_dir_next();
  2899.  
  2900.   for (int n = 0; n < weaponsNum;)
  2901.     {
  2902.       assert(weaponCurrent <= weaponsNum);
  2903.  
  2904.       PhysicalP p;
  2905.       if (p = locator->lookup(weapons[n]))
  2906.     {
  2907.       if ((((WeaponP)p)->get_ammo() > 0) || 
  2908.           (((WeaponP)p)->get_ammo() == PH_AMMO_UNLIMITED))
  2909.         ((WeaponP)p)->follow_user(middleNext,dirNext);
  2910.       else
  2911.         p->kill_self();
  2912.       n++;
  2913.     }
  2914.       else
  2915.     {
  2916.       weapons[n] = weapons[weaponsNum - 1];
  2917.       weaponsNum--;
  2918.  
  2919.       if (weaponCurrent == weaponsNum && n != weaponsNum)
  2920.         weaponCurrent = n; // Keep same current weapon.
  2921.       else if (weaponCurrent == weaponsNum + 1)
  2922.         weaponCurrent = weaponsNum;  // So still no weapon.
  2923.       else if (weaponCurrent == n)
  2924.         weaponCurrent = defaultable_weapon(); // Still some weapon active.
  2925.  
  2926.       PhysicalP weapon;
  2927.       if ((weaponCurrent != weaponsNum) && 
  2928.           (weapon = locator->lookup(weapons[weaponCurrent])))
  2929.         ((WeaponP)weapon)->enter_scope_next(this);
  2930.     }
  2931.     }
  2932.  
  2933.   for (n = 0; n < itemsNum;)
  2934.     {
  2935.       assert(itemCurrent <= itemsNum);
  2936.  
  2937.       PhysicalP p;
  2938.       if (p = locator->lookup(items[n]))
  2939.     {
  2940.       ((ItemP)p)->follow_user(middleNext,dirNext);
  2941.       n++;
  2942.     }
  2943.       else
  2944.     {
  2945.       items[n] = items[itemsNum - 1];
  2946.       itemsNum--;
  2947.  
  2948.       if (itemCurrent == itemsNum && n != itemsNum)
  2949.         itemCurrent = n; // Keep same current item.
  2950.       else if (itemCurrent == itemsNum + 1)
  2951.         itemCurrent = itemsNum;  // So still no item.
  2952.       else if (itemCurrent == n)
  2953.         itemCurrent = 0;  // Some item or itemsNum.
  2954.     }
  2955.     }
  2956.  
  2957.   assert(weaponCurrent <= weaponsNum);
  2958.   assert(itemCurrent <= itemsNum);
  2959. }
  2960.  
  2961.  
  2962.  
  2963. void User::collide(PhysicalP other) 
  2964. {
  2965.   if (!_collide(other)) 
  2966.     Creature::collide(other);
  2967. }
  2968.  
  2969.  
  2970.  
  2971. Boolean User::_collide(PhysicalP other)
  2972.   if (alive() && other->is_item() && ((ItemP)other)->can_take())
  2973.     {
  2974.       // Pick up weapon.
  2975.       if (other->is_weapon() && (weaponsNum < PH_WEAPONS_MAX))
  2976.     {
  2977.       ((ItemP)other)->taken(this);
  2978.       
  2979.       WeaponP weapon;
  2980.       if (has_weapon(&weapon,other->get_class_id()))
  2981.         { 
  2982.           // Take ammo from other and kill other.
  2983.           weapon->take_ammo_from((WeaponP)other);
  2984.           other->set_quiet_death();
  2985.           other->kill_self();
  2986.         }
  2987.       else  
  2988.         {
  2989.           weapons[weaponsNum] = other->get_id();
  2990.           weaponsNum++;
  2991.  
  2992.           /* Automatically switch to weapon if no previous weapon. */ 
  2993.           if (weaponCurrent == weaponsNum - 1)
  2994.         {
  2995. //          if (((WeaponP)other)->defaultable())
  2996.           ((WeaponP)other)->enter_scope_next(this);
  2997. //          else
  2998. //            weaponCurrent = weaponsNum;
  2999.         }
  3000.         }
  3001.     }
  3002.  
  3003.       // Pick up item.
  3004.       else if (itemsNum < PH_ITEMS_MAX)
  3005.     {
  3006.       ((ItemP)other)->taken(this);
  3007.  
  3008.       items[itemsNum] = other->get_id();
  3009.       itemsNum++;
  3010.  
  3011.       // itemCurrent is 0 if no previous item.
  3012.     }
  3013.  
  3014.       return True;
  3015.     }
  3016.   else
  3017.     return False;
  3018. }
  3019.  
  3020.  
  3021.  
  3022. void User::die()
  3023. {
  3024.   _die();
  3025.   Creature::die();
  3026. }
  3027.  
  3028.  
  3029.  
  3030. void User::_die()
  3031. {
  3032.   LocatorP locator = get_locator();
  3033.  
  3034.   // Drop all weapons.
  3035.   for (int n = 0; n < weaponsNum; n++)
  3036.     {
  3037.       PhysicalP weapon;
  3038.       if (locator->lookup(weapon,weapons[n]) == OL_NO_SIG)
  3039.     {
  3040.       if (n == weaponCurrent)
  3041.         ((WeaponP)weapon)->leave_scope_next(this);
  3042.  
  3043.       if (((ItemP)weapon)->persists())
  3044.         ((ItemP)weapon)->dropped(this);
  3045.       else if (!weapon->die_called())
  3046.         {
  3047.           weapon->set_quiet_death();
  3048.           weapon->kill_self();
  3049.           weapon->die();
  3050.         }
  3051.     }
  3052.     }
  3053.   weaponCurrent = 0;
  3054.   weaponsNum = 0;
  3055.  
  3056.  
  3057.   // Drop all items.
  3058.   itemCurrent = 0;
  3059.   for (n = 0; n < itemsNum; n++)
  3060.     {
  3061.       PhysicalP item;
  3062.       if (locator->lookup(item,items[n]) == OL_NO_SIG)
  3063.     {
  3064.       if (((ItemP)item)->persists())
  3065.         ((ItemP)item)->dropped(this);
  3066.       else if (!item->die_called())
  3067.         {
  3068.           item->set_quiet_death();
  3069.           item->kill_self();
  3070.           item->die();
  3071.         }
  3072.     }
  3073.     }
  3074.   itemsNum = 0;
  3075. }
  3076.  
  3077.  
  3078.  
  3079. Boolean User::has_weapon(Weapon **weaponOut,ClassId classId)
  3080. {
  3081.   for (int n = 0; n < weaponsNum; n++)
  3082.     {
  3083.       PhysicalP weapon;
  3084.       LocatorP locator = get_locator();
  3085.  
  3086.       // Clean up deleted weapons elsewhere.
  3087.       if (weapon = locator->lookup(weapons[n]))
  3088.     if (weapon->get_class_id() == classId)
  3089.       {
  3090.         if (weaponOut)
  3091.           *weaponOut = (WeaponP)weapon;
  3092.         return True;
  3093.       }
  3094.     }
  3095.   return False;
  3096. }
  3097.  
  3098.  
  3099.  
  3100. int User::defaultable_weapon()
  3101. {
  3102.   for (int n = 0; n < weaponsNum; n++)
  3103.     {
  3104.       LocatorP locator = get_locator();
  3105.       WeaponP weapon = (WeaponP)locator->lookup(weapons[n]);
  3106.       if (weapon && weapon->defaultable())
  3107.     return n;
  3108.     }
  3109.   return weaponsNum;
  3110. }
  3111.  
  3112.  
  3113.  
  3114. Fighter::Fighter(const FighterContext &f_c,
  3115.          FighterXdata &x_data)
  3116. {
  3117.   Timer nTimer(FIGHTER_SLIDE_TIME);
  3118.   stuckTimer = nTimer;
  3119.  
  3120.   fc = &f_c;
  3121.   fighterXdata = &x_data;
  3122.   attack = attackNext = attackNone;
  3123. }
  3124.  
  3125.  
  3126.  
  3127. Boolean Fighter::is_fighter()
  3128. {
  3129.   return True;
  3130. }
  3131.  
  3132.  
  3133.  
  3134. void Fighter::get_pixmap_mask(int dpyNum,Pixmap &pixmap,Pixmap &mask,
  3135.                   Dir dir,int animNum)
  3136. {
  3137.   // Alive check is somewhat of a hack.
  3138.   if (alive() && attack && dir_to_attack(dir))
  3139.     {
  3140.       pixmap = fighterXdata->pixmaps[dpyNum][dir];
  3141.       mask = fighterXdata->masks[dpyNum][dir];
  3142.     }
  3143.   else
  3144.     Creature::get_pixmap_mask(dpyNum,pixmap,mask,dir,animNum);
  3145. }
  3146.  
  3147.  
  3148.   
  3149. void Fighter::get_size_offset_next(Size &size,Size &offset,
  3150.                        Dir dirNext)
  3151. {
  3152.   // Alive check is somewhat of a hack.
  3153.   if (alive_next() && attackNext && dir_to_attack(dirNext))
  3154.     {
  3155.       size = fc->sizes[dirNext];
  3156.       offset = fc->offsets[dirNext];
  3157.     }
  3158.   else
  3159.     Creature::get_size_offset_next(size,offset,dirNext);
  3160. }
  3161.  
  3162.  
  3163.                  
  3164. void Fighter::act() 
  3165. {
  3166.   _act(); 
  3167.   Creature::act();
  3168. }
  3169.  
  3170.  
  3171.  
  3172. void Fighter::_act()
  3173. {
  3174.   ITcommand command = get_command();
  3175.   const Dir dir = get_dir();
  3176.  
  3177.   if (attack && (attack != dir_to_attack(dir)))
  3178.     {
  3179.       attackNext = attackNone;
  3180.       set_vel_next(0);
  3181.     }
  3182.  
  3183.   if (attack == attackStuck) 
  3184.     {
  3185.       if (stuckTimer.ready())
  3186.     {
  3187.       attackNext = attackNone;
  3188.       set_vel_next(0);
  3189.     }
  3190.       else
  3191.     stuckTimer.clock();
  3192.     }
  3193.   
  3194.   // Start new attack.
  3195.   if (!attack && !get_weapon_current() && Intel::is_command_weapon(command))
  3196.     {
  3197.       // Choose attack depending on stance.
  3198.       switch (get_stance()) {
  3199.       case CO_center:
  3200.     switch (command) {
  3201.     case IT_WEAPON_R:
  3202.       attack_stuck(CO_center_R,CO_center);
  3203.       break;
  3204.     case IT_WEAPON_DN_R:
  3205.       attack_stuck(CO_dn_R,CO_dn);
  3206.       break;
  3207.     case IT_WEAPON_DN_L:
  3208.       attack_stuck(CO_dn_L,CO_dn);
  3209.       break;
  3210.     case IT_WEAPON_L:
  3211.       attack_stuck(CO_center_L,CO_center);
  3212.       break;
  3213.     case IT_WEAPON_UP_L:
  3214.       attack_free_horizontal(CO_UP_L);  
  3215.       break;
  3216.     case IT_WEAPON_UP:
  3217.       attack_free_vertical(CO_air_UP);
  3218.       break;
  3219.     case IT_WEAPON_UP_R:
  3220.       attack_free_horizontal(CO_UP_R); 
  3221.       break;
  3222.     };
  3223.     break;
  3224.  
  3225.       case CO_air: 
  3226.     if (command == IT_WEAPON_DN)
  3227.       attack_free_vertical(CO_air_DN);
  3228.     break;
  3229.     
  3230.       case CO_r:
  3231.     switch (command) {
  3232.     case IT_WEAPON_L:
  3233.     case IT_WEAPON_DN_L:
  3234.       attack_free_horizontal(CO_center_L);
  3235.       break;
  3236.     case IT_WEAPON_UP_L:
  3237.       attack_free_horizontal(CO_UP_L);
  3238.       break;
  3239.     case IT_WEAPON_UP:
  3240.     case IT_WEAPON_UP_R:
  3241.       attack_stuck(CO_r_UP,CO_r);
  3242.       break;
  3243.     case IT_WEAPON_DN:
  3244.     case IT_WEAPON_DN_R:
  3245.       attack_stuck(CO_r_DN,CO_r);
  3246.       break;
  3247.     };
  3248.     break;
  3249.  
  3250.       case CO_dn:
  3251.     switch (command) {
  3252.     case IT_WEAPON_UP_R:
  3253.       attack_free_horizontal(CO_UP_R);
  3254.       break;
  3255.     case IT_WEAPON_UP_L:
  3256.       attack_free_horizontal(CO_UP_L);
  3257.       break;
  3258.     case IT_WEAPON_UP:
  3259.       attack_free_vertical(CO_air_UP);
  3260.       break;
  3261.     case IT_WEAPON_R:
  3262.     case IT_WEAPON_DN_R:
  3263.       attack_stuck(CO_dn_R,CO_dn);
  3264.       break;
  3265.     case IT_WEAPON_L:
  3266.     case IT_WEAPON_DN_L:
  3267.       attack_stuck(CO_dn_L,CO_dn);
  3268.       break;
  3269.     };
  3270.     break;
  3271.  
  3272.       case CO_l:
  3273.     switch (command) {
  3274.     case IT_WEAPON_R:
  3275.     case IT_WEAPON_DN_R:
  3276.       attack_free_horizontal(CO_center_R);
  3277.       break;
  3278.     case IT_WEAPON_UP_R:
  3279.       attack_free_horizontal(CO_UP_R);
  3280.       break;
  3281.     case IT_WEAPON_UP:
  3282.     case IT_WEAPON_UP_L:
  3283.       attack_stuck(CO_l_UP,CO_l);
  3284.       break;
  3285.     case IT_WEAPON_DN:
  3286.     case IT_WEAPON_DN_L:
  3287.       attack_stuck(CO_l_DN,CO_l);
  3288.       break;
  3289.     };
  3290.     break;
  3291.  
  3292.       case CO_up:
  3293.     switch (command) {
  3294.     case IT_WEAPON_DN:
  3295.       attack_free_vertical(CO_air_DN);
  3296.       break;
  3297.     case IT_WEAPON_R:
  3298.     case IT_WEAPON_DN_R:
  3299.     case IT_WEAPON_UP_R:
  3300.       attack_stuck(CO_up_R,CO_up);
  3301.       break;
  3302.     case IT_WEAPON_L:
  3303.     case IT_WEAPON_DN_L:
  3304.     case IT_WEAPON_UP_L:
  3305.       attack_stuck(CO_up_L,CO_up);
  3306.       break;
  3307.     };
  3308.     break;
  3309.  
  3310.       case CO_climb:
  3311.     switch (command) {
  3312.     case IT_WEAPON_R:
  3313.     case IT_WEAPON_DN_R:
  3314.       attack_free_horizontal(CO_center_R);
  3315.       break;
  3316.     case IT_WEAPON_DN:
  3317.       attack_free_vertical(CO_air_DN);
  3318.       break;
  3319.     case IT_WEAPON_L:
  3320.     case IT_WEAPON_DN_L:
  3321.       attack_free_horizontal(CO_center_L);
  3322.       break;
  3323.     case IT_WEAPON_UP_L:
  3324.       attack_free_horizontal(CO_UP_L);
  3325.       break;
  3326.     case IT_WEAPON_UP:
  3327.       attack_free_vertical(CO_air_UP);
  3328.       break;
  3329.     case IT_WEAPON_UP_R:
  3330.       attack_free_horizontal(CO_UP_R);
  3331.       break;
  3332.     };
  3333.       };
  3334.     }  
  3335. }
  3336.  
  3337.  
  3338.  
  3339. void Fighter::update() 
  3340. {
  3341.   _update(); 
  3342.   Creature::update();
  3343. }
  3344.  
  3345.  
  3346.  
  3347. void Fighter::_update()
  3348. {
  3349.   attack = attackNext;
  3350. }
  3351.  
  3352.  
  3353.  
  3354. void Fighter::collide(PhysicalP other)
  3355. {
  3356.   if (!_collide(other)) 
  3357.     Creature::collide(other);
  3358. }
  3359.  
  3360.  
  3361.  
  3362. Boolean Fighter::_collide(PhysicalP other)
  3363. {
  3364.   if (attack)
  3365.     {
  3366.       Dir dir = get_dir();
  3367.       const Area &area = get_area();
  3368.       
  3369.       Pos pos;
  3370.       Size size;
  3371.       area.get_rect(pos,size);
  3372.       
  3373.       const Area &otherArea = other->get_area();
  3374.       Attack attackDir = dir_to_attack(dir);
  3375.  
  3376.  
  3377.       if (attackDir && otherArea.overlap(pos + fc->hotSpots[dir]))
  3378.     {
  3379.       // Move just enough to get out of the way.
  3380.       Size offset = area.avoid(otherArea);
  3381.       const Pos &rawPos = get_raw_pos();
  3382.       set_raw_pos_next(rawPos + offset);
  3383.  
  3384.       other->corporeal_attack(this,
  3385.                   (attackDir == attackStuck) ? 
  3386.                   fc->damageStuck : fc->damageFree);
  3387.       attackNext = attackNone;
  3388.       return True;
  3389.     }
  3390.     }
  3391.   
  3392.   return False;
  3393. }
  3394.  
  3395.  
  3396.  
  3397. void Fighter::init_x(Xvars &xvars)
  3398. {
  3399.   assert(fighterXdata->valid == False);
  3400.  
  3401.   for (int dpyNum = 0; dpyNum < xvars.dpyMax; dpyNum++)
  3402.     for (int n = 0; n < CO_DIR_MAX; n++)
  3403.       if (dir_to_attack(n) && fc->pixmapBits[n] && fc->maskBits[n])
  3404.     {
  3405.       fighterXdata->pixmaps[dpyNum][n] = 
  3406.         XCreatePixmapFromBitmapData(xvars.dpy[dpyNum],xvars.root[dpyNum],
  3407.                     fc->pixmapBits[n],
  3408.                     fc->sizes[n].width,fc->sizes[n].height,
  3409.                     xvars.black[dpyNum],
  3410.                     xvars.allocNamedColor(dpyNum,fc->colorName),
  3411.                     xvars.depth[dpyNum]);
  3412.       fighterXdata->masks[dpyNum][n] = 
  3413.         XCreateBitmapFromData(xvars.dpy[dpyNum],xvars.root[dpyNum],
  3414.                   fc->maskBits[n],
  3415.                   fc->sizes[n].width,fc->sizes[n].height);
  3416.     }
  3417.   
  3418.   fighterXdata->valid = True;
  3419.   Creature::init_x(xvars);
  3420. }
  3421.  
  3422.  
  3423.  
  3424. Attack Fighter::dir_to_attack(Dir dir)
  3425. {
  3426.   switch (dir) {
  3427.   case CO_center_R:
  3428.   case CO_center_L:
  3429.   case CO_r_DN:
  3430.   case CO_r_UP:
  3431.   case CO_dn_R:
  3432.   case CO_dn_L:
  3433.   case CO_l_DN:
  3434.   case CO_l_UP:
  3435.   case CO_up_R:
  3436.   case CO_up_L:
  3437.     return attackStuck;
  3438.  
  3439.   case CO_air_R:
  3440.   case CO_air_DN: 
  3441.   case CO_air_L:
  3442.   case CO_air_UP:
  3443.     return attackFree;
  3444.   };
  3445.  
  3446.   return attackNone;
  3447. }
  3448.  
  3449.  
  3450.  
  3451. void Fighter::attack_stuck(Dir dir,Stance stance)
  3452. {
  3453.   const Vel *unitVels = get_unit_vels();
  3454.  
  3455.   set_vel_next(fc->slide * unitVels[dir]);
  3456.   set_stance_next(stance);
  3457.   stuckTimer.set();
  3458.   attackNext = attackStuck;
  3459. }
  3460.  
  3461.  
  3462.  
  3463. void Fighter::attack_free_horizontal(Dir dir)
  3464. {
  3465.   const Acc *unitAccs = get_unit_accs();
  3466.  
  3467.   set_vel_next(get_vel() + fc->jumpHorizontal * unitAccs[dir]);
  3468.   set_stance_next(CO_air);
  3469.   attackNext = attackFree;
  3470. }
  3471.  
  3472.  
  3473.  
  3474. void Fighter::attack_free_vertical(Dir dir)
  3475. {
  3476.   const Acc *unitAccs = get_unit_accs();
  3477.   Vel vel = get_vel();
  3478.  
  3479.   Vel velNext(0,vel.dy + fc->jumpVertical * unitAccs[dir].ddy);
  3480.   set_vel_next(velNext);
  3481.   set_stance_next(CO_air);
  3482.   attackNext = attackFree;
  3483. }
  3484.  
  3485.  
  3486.  
  3487. Walking::Walking(const WalkingContext &,WalkingXdata &)
  3488. {}
  3489.  
  3490.  
  3491.  
  3492. void Walking::act()
  3493. {
  3494.   _act();
  3495.   Creature::act();
  3496. }
  3497.  
  3498.  
  3499.  
  3500. void Walking::_act()
  3501. {
  3502.   const Vel vel = get_vel();
  3503.   const Pos &rawPos = get_raw_pos();
  3504.  
  3505.   // Avoid getting stuck.
  3506. /*  if (alive() && velPrev.dy > 0 && rawPosPrev == rawPos)
  3507.     {
  3508.       Vel velNext(0,vel.dy);
  3509.       set_vel_next(velNext);
  3510. #ifdef PRINT_ERRORS
  3511.       cerr << "Walking::_act()  trying to get unstuck." << endl;
  3512. #endif
  3513.       return;
  3514.     }
  3515.     
  3516.   velPrev = vel;
  3517.   rawPosPrev = rawPos;
  3518.   */
  3519.  
  3520.   // Methods of Moving or Creature.
  3521.   const CreatureContext *cc = get_creature_context();
  3522.   const Stance stance = get_stance();
  3523.   const Touching touchingArea = get_touching_area();
  3524.   const Touching touchingStance = get_touching_stance();
  3525.   const Acc *unitAccs = get_unit_accs();
  3526.   const Boolean canClimb = can_climb();
  3527.   const Area area = get_area();
  3528.   const ITcommand command = get_command(); 
  3529.   
  3530.   
  3531.   // Default set gravity.
  3532.   set_grav_next((touchingArea == CO_dn) || 
  3533.         (canClimb && (stance == CO_climb) && alive()) ? 0 : GRAVITY);
  3534.  
  3535.   
  3536.   // Change stance if necessary.
  3537.   if (stance != CO_climb) 
  3538.     {
  3539.       if (touchingArea != touchingStance)
  3540.     {
  3541.       // Hit the ground.
  3542.       if (touchingArea == CO_dn) 
  3543.         {
  3544.           set_stance_next(CO_center);
  3545.           Vel velNew(vel.dx,0);
  3546.           set_vel_next(velNew);
  3547.         }
  3548.       // Side walls.
  3549.       else if (touchingArea == CO_r)
  3550.         {
  3551.           Vel velNew(1,vel.dy);
  3552.           set_vel_next(velNew);
  3553.         }
  3554.       else if (touchingArea == CO_l)
  3555.         {
  3556.           Vel velNew(-1,vel.dy);
  3557.           set_vel_next(velNew);
  3558.         }
  3559.       // In the air.
  3560.       else if (touchingArea == CO_air)
  3561.         {
  3562.           // Disabled automatically grabbing ladders.
  3563. /*          if (canClimb && (stance == CO_center))
  3564.         {
  3565.           set_stance_next(CO_climb);
  3566.           set_vel_next(0);
  3567.           set_grav_next(0);
  3568.           center_wsquare_x_next(area.middle_wsquare());
  3569.         }
  3570.           else */
  3571.         set_stance_next(CO_air);
  3572.         }
  3573.       else if (touchingArea != CO_up)
  3574.         assert(0);
  3575.     }
  3576.       else if (touchingArea == CO_dn) 
  3577.     {
  3578.       Vel velNew(vel.dx,0);
  3579.       set_vel_next(velNew);
  3580.     }
  3581.     }
  3582.   // Stop climbing if not in climbing square. 
  3583.   else if (!canClimb)  // stance == CO_climb
  3584.     set_stance_next(CO_air);
  3585.   
  3586.   
  3587.   /* Interpret commands from controlling intelligence.  May override some of 
  3588.      above settings. */
  3589.   switch (command) {
  3590.   case IT_CENTER:
  3591.     if ((stance != CO_climb) && canClimb)
  3592.       {
  3593.     set_stance_next(CO_climb);
  3594.     set_vel_next(0);
  3595.     set_grav_next(0);
  3596.     center_wsquare_x_next(area.middle_wsquare());
  3597.       }
  3598.     else if (stance != CO_air)
  3599.       set_vel_next(0);
  3600.     break;
  3601.     
  3602.   case IT_R:
  3603.     if ((stance == CO_dn) || (stance == CO_center) || // Regular walking.
  3604.     (stance == CO_climb)) 
  3605.       set_vel_next(vel + cc->acceleration * unitAccs[CO_center_R]);
  3606.     break;
  3607.     
  3608.   case IT_DN_R:
  3609.     if (stance == CO_dn)
  3610.       set_vel_next(vel + cc->acceleration * unitAccs[CO_dn_R]);
  3611.     else if (stance == CO_center) // Crawling.
  3612.       {
  3613.     set_vel_next(vel + cc->acceleration * unitAccs[CO_dn_R]);
  3614.     set_stance_next(CO_dn);
  3615.       }
  3616.     else if (stance == CO_climb)
  3617.       set_vel_next(vel + cc->acceleration * unitAccs[CO_center_R]);
  3618.     break;
  3619.     
  3620.   case IT_DN:
  3621.     if ((stance != CO_climb) && canClimb)
  3622.       {
  3623.     set_stance_next(CO_climb);
  3624.     set_vel_next(0);
  3625.     set_grav_next(0);
  3626.     center_wsquare_x_next(area.middle_wsquare());
  3627.       }
  3628.     // slow down.
  3629.     else if (stance == CO_dn) 
  3630.       set_vel_next(0);
  3631.     else if (stance == CO_center) 
  3632.       set_stance_next(CO_dn);
  3633.     else if (stance == CO_climb)
  3634.       set_vel_next(vel + cc->acceleration * unitAccs[CO_climb_DN]);
  3635.     break;
  3636.     
  3637.   case IT_DN_L:
  3638.     if (stance == CO_dn) // Crawling.
  3639.       set_vel_next(vel + cc->acceleration * unitAccs[CO_dn_L]);
  3640.     else if (stance == CO_center) // Crawling.
  3641.       {
  3642.     set_vel_next(vel + cc->acceleration * unitAccs[CO_dn_L]);
  3643.     set_stance_next(CO_dn);
  3644.       }
  3645.     else if (stance == CO_climb) 
  3646.       set_vel_next(vel + cc->acceleration * unitAccs[CO_center_L]);
  3647.     break;
  3648.     
  3649.   case IT_L:
  3650.     if ((stance == CO_dn) || (stance == CO_center) || // Regular walking.
  3651.     (stance == CO_climb)) 
  3652.       set_vel_next(vel + cc->acceleration * unitAccs[CO_center_L]);
  3653.     break;
  3654.     
  3655.   case IT_UP_L:
  3656.     if ((stance == CO_dn) || (stance == CO_center) || (stance == CO_climb)) 
  3657.       { // Jump left.
  3658.     set_vel_next(vel + cc->jump * unitAccs[CO_air_L]);
  3659.     set_stance_next(CO_air);
  3660.       }
  3661.     break;
  3662.     
  3663.   case IT_UP:
  3664.     if ((stance != CO_climb) && canClimb)
  3665.       {
  3666.     set_stance_next(CO_climb);
  3667.     set_vel_next(0);
  3668.     set_grav_next(0);
  3669.     center_wsquare_x_next(area.middle_wsquare());
  3670.       }
  3671.     else if (stance == CO_dn)
  3672.       set_stance_next(CO_center);
  3673.     else if (stance == CO_center) // Jump up.
  3674.       {
  3675.     set_vel_next(vel + cc->jump * unitAccs[CO_air_UP]);
  3676.     set_stance_next(CO_air);
  3677.       }
  3678.     else if (stance == CO_climb)
  3679.       set_vel_next(vel + cc->acceleration * unitAccs[CO_climb_UP]);
  3680.     break;
  3681.     
  3682.   case IT_UP_R:
  3683.     // Jump right.
  3684.     if ((stance == CO_dn) || (stance == CO_center) || (stance == CO_climb)) 
  3685.       { 
  3686.     set_vel_next(vel + cc->jump * unitAccs[CO_air_R]);
  3687.     set_stance_next(CO_air);
  3688.       }
  3689.     break;
  3690.   }
  3691. }
  3692.  
  3693.  
  3694.  
  3695. Sticky::Sticky(const StickyContext &,StickyXdata &)
  3696. {
  3697.   wantCorner1 = wantCorner2 = CO_air;
  3698. }
  3699.  
  3700.  
  3701.  
  3702. Boolean Sticky::is_sticky()
  3703. {
  3704.   return True;
  3705. }
  3706.  
  3707.  
  3708.  
  3709. void Sticky::act() 
  3710. {
  3711.   _act(); 
  3712.   Creature::act();
  3713. }
  3714.  
  3715.  
  3716.  
  3717. void Sticky::_act()
  3718. {
  3719.   // Methods of Moving or Creature.
  3720.   const CreatureContext *cc = get_creature_context();
  3721.   const Stance stance = get_stance();
  3722.   const Touching touchingArea = get_touching_area();
  3723.   const Touching touchingStance = get_touching_stance();
  3724.   const Hanging hanging = get_hanging();
  3725.   const Vel vel = get_vel();
  3726.   const Acc *unitAccs = get_unit_accs();
  3727.   const Boolean canClimb = can_climb();
  3728.   const Area area = get_area();
  3729.   const ITcommand command = get_command(); 
  3730.   
  3731.   /* Set gravity.  Don't lock on walls if dead. */
  3732.   set_grav_next((!alive() && (touchingArea != CO_dn)) ||
  3733.         ((touchingArea == CO_air) && 
  3734.          !(canClimb && (stance == CO_climb))) 
  3735.         ? GRAVITY : 0);
  3736.   
  3737.   /* Make stance correspond to touching.  I.e. attach / detach to wall.
  3738.      Do not attach to wall if climbing. */
  3739.   if ((stance != CO_climb) || !canClimb)
  3740.     {
  3741.       if ((touchingArea != touchingStance) || 
  3742.       ((stance == CO_climb) && !canClimb))
  3743.     {
  3744.       if (touchingArea == CO_dn)
  3745.         {
  3746.           set_stance_next(CO_center);
  3747.           Vel velNew(vel.dx,0);
  3748.           set_vel_next(velNew);
  3749.         }
  3750.       else if (touchingArea == CO_r)
  3751.         {
  3752.           set_stance_next(CO_r);
  3753.           set_vel_next(0);
  3754.         }
  3755.       else if (touchingArea == CO_l)
  3756.         {
  3757.           set_stance_next(CO_l);
  3758.           set_vel_next(0);
  3759.         }
  3760.       else if (touchingArea == CO_up)
  3761.         {
  3762.           set_stance_next(CO_up);
  3763.           set_vel_next(0);
  3764.         }
  3765.       else if (touchingArea == CO_air)
  3766.         {
  3767.           // Disabled automatically grabbing ladders.
  3768. /*          if (canClimb && (stance == CO_center))
  3769.         {
  3770.           set_stance_next(CO_climb);
  3771.           set_vel_next(0);
  3772.           set_grav_next(0);
  3773.           center_wsquare_x_next(area.middle_wsquare());
  3774.         }
  3775.           else */
  3776.         set_stance_next(CO_air);
  3777.         }
  3778.       else
  3779.         assert(0);
  3780.     }
  3781.       else if ((touchingArea == CO_dn) || (touchingArea == CO_up))
  3782.     {
  3783.       Vel velNew(vel.dx,0);
  3784.       set_vel_next(velNew);
  3785.     }
  3786.       else if ((touchingArea == CO_r) || (touchingArea == CO_l))
  3787.     {
  3788.       Vel velNew(0,vel.dy);
  3789.       set_vel_next(velNew);
  3790.     }
  3791.     }
  3792.   // Stop climbing if not in climbing square. 
  3793. //  else if (! canClimb) // stance == CO_climb
  3794. //    set_stance_next(CO_air);
  3795.   
  3796.  
  3797.   /* Interpret commands from controlling intelligence.  May override some of 
  3798.      above settings. */
  3799.   switch (command) {
  3800.   case IT_CENTER:
  3801.     set_want_corner(CO_air);  
  3802.     if ((stance != CO_climb) && canClimb)
  3803.       {
  3804.     set_stance_next(CO_climb);
  3805.     set_vel_next(0);
  3806.     set_grav_next(0);
  3807.     center_wsquare_x_next(area.middle_wsquare());
  3808.       }
  3809.     else if (stance != CO_air)
  3810.       set_vel_next(0);
  3811.     break;
  3812.     
  3813.   case IT_R:
  3814.     set_want_corner(CO_air);  
  3815.     if (stance == CO_r) // On right wall.
  3816.       {
  3817.     set_vel_next(0);
  3818.     set_want_corner(CO_r_UP,CO_r_DN);
  3819.       }
  3820.     else if ((stance == CO_dn) || (stance == CO_center) || // Regular walking.
  3821.          (stance == CO_climb)) 
  3822.       set_vel_next(vel + cc->acceleration * unitAccs[CO_center_R]);
  3823.     else if (stance == CO_l) // On left wall.
  3824.       set_vel_next(vel + PUSH_OFF * unitAccs[CO_R]);
  3825.     else if (stance == CO_up) // On ceiling.
  3826.       set_vel_next(vel + cc->acceleration * unitAccs[CO_up_R]);
  3827.     break;
  3828.     
  3829.   case IT_DN_R:
  3830.     set_want_corner(CO_air);  
  3831.     if (stance == CO_r) // On right wall.
  3832.       {
  3833.     set_want_corner(CO_r_DN);
  3834.     set_vel_next(vel + cc->acceleration * unitAccs[CO_r_DN]);
  3835.       }
  3836.     else if (stance == CO_dn)
  3837.       {
  3838.     set_want_corner(CO_dn_R);
  3839.     set_vel_next(vel + cc->acceleration * unitAccs[CO_dn_R]);
  3840.       }
  3841.     else if ((stance == CO_l) || (stance == CO_up)) 
  3842.       set_vel_next(vel + PUSH_OFF * unitAccs[CO_DN_R]);
  3843.     else if (stance == CO_center) // Crawling.
  3844.       {
  3845.     set_vel_next(vel + cc->acceleration * unitAccs[CO_dn_R]);
  3846.     set_stance_next(CO_dn);
  3847.       }
  3848.     else if (stance == CO_climb)
  3849.       set_vel_next(vel + cc->acceleration * unitAccs[CO_center_R]);
  3850.     break;
  3851.     
  3852.   case IT_DN:
  3853.     set_want_corner(CO_air);  
  3854.     if ((stance != CO_climb) && canClimb)
  3855.       {
  3856.     set_stance_next(CO_climb);
  3857.     set_vel_next(0);
  3858.     set_grav_next(0);
  3859.     center_wsquare_x_next(area.middle_wsquare());
  3860.       }
  3861.     else if (stance == CO_dn) 
  3862.       {
  3863.     set_vel_next(0);
  3864.     set_want_corner(CO_dn_R,CO_dn_L);
  3865.       }
  3866.     else if (stance == CO_center)  // duck
  3867.       set_stance_next(CO_dn);
  3868.     else if (stance == CO_up)
  3869.       set_vel_next(vel + PUSH_OFF * unitAccs[CO_DN]);
  3870.     else if (stance == CO_r)
  3871.       set_vel_next(vel + cc->acceleration * unitAccs[CO_r_DN]);
  3872.     else if (stance == CO_l)
  3873.       set_vel_next(vel + cc->acceleration * unitAccs[CO_l_DN]);    
  3874.     else if (stance == CO_climb)
  3875.       set_vel_next(vel + cc->acceleration * unitAccs[CO_climb_DN]);
  3876.     break;
  3877.     
  3878.   case IT_DN_L:
  3879.     set_want_corner(CO_air);  
  3880.     if ((stance == CO_r) || (stance == CO_up)) // On other walls.
  3881.       set_vel_next(vel + PUSH_OFF * unitAccs[CO_DN_L]);
  3882.     else if (stance == CO_dn) // Crawling.
  3883.       {
  3884.     set_want_corner(CO_dn_L);
  3885.     set_vel_next(vel + cc->acceleration * unitAccs[CO_dn_L]);
  3886.       }
  3887.     else if (stance == CO_l) // On left wall.
  3888.       {
  3889.     set_want_corner(CO_l_DN);
  3890.     set_vel_next(vel + cc->acceleration * unitAccs[CO_l_DN]);
  3891.       }
  3892.     else if (stance == CO_center) // Crawling.
  3893.       {
  3894.     set_vel_next(vel + cc->acceleration * unitAccs[CO_dn_L]);
  3895.     set_stance_next(CO_dn);
  3896.       }
  3897.     else if (stance == CO_climb) 
  3898.       set_vel_next(vel + cc->acceleration * unitAccs[CO_center_L]);
  3899.     break;
  3900.     
  3901.   case IT_L:
  3902.     set_want_corner(CO_air);  
  3903.     if (stance == CO_l) // On left wall.
  3904.       {
  3905.     set_want_corner(CO_l_DN,CO_l_UP);
  3906.     set_vel_next(0);
  3907.       }
  3908.     else if ((stance == CO_dn) || (stance == CO_center) || // Regular walking.
  3909.          (stance == CO_climb)) 
  3910.       set_vel_next(vel + cc->acceleration * unitAccs[CO_center_L]);
  3911.     else if (stance == CO_r) // On right wall.
  3912.       set_vel_next(vel +  PUSH_OFF * unitAccs[CO_L]);
  3913.     else if (stance == CO_up) // On ceiling.
  3914.       set_vel_next(vel + cc->acceleration * unitAccs[CO_up_L]);
  3915.     break;
  3916.     
  3917.   case IT_UP_L:
  3918.     set_want_corner(CO_air);  
  3919.     if ((stance == CO_r) || (stance == CO_dn) || (stance == CO_center) ||
  3920.     (stance == CO_climb)) 
  3921.       { // Jump left.
  3922.     set_vel_next(vel + cc->jump * unitAccs[CO_air_L]);
  3923.     set_stance_next(CO_air);
  3924.       }
  3925.     else if (stance == CO_l) // On left wall.
  3926.       {
  3927.     set_want_corner(CO_l_UP);
  3928.     set_vel_next(vel + cc->acceleration * unitAccs[CO_l_UP]);
  3929.       }
  3930.     else if (stance == CO_up) // On ceiling.
  3931.       {
  3932.     set_want_corner(CO_up_L);
  3933.     set_vel_next(vel + cc->acceleration * unitAccs[CO_up_L]);
  3934.       }
  3935.     break;
  3936.     
  3937.   case IT_UP:
  3938.     set_want_corner(CO_air);  
  3939.     if ((stance != CO_climb) && canClimb)
  3940.       {
  3941.     set_stance_next(CO_climb);
  3942.     set_vel_next(0);
  3943.     set_grav_next(0);
  3944.     center_wsquare_x_next(area.middle_wsquare());
  3945.       }
  3946.     else if (stance == CO_up) // On ceiling.
  3947.       {
  3948.     set_want_corner(CO_up_R,CO_up_L);
  3949.     set_vel_next(0);
  3950.       }
  3951.     else if (stance == CO_dn) 
  3952.       set_stance_next(CO_center);
  3953.     else if (stance == CO_center) // Jump up.
  3954.       {
  3955.     set_vel_next(vel + cc->jump * unitAccs[CO_air_UP]);
  3956.     set_stance_next(CO_air);
  3957.       }
  3958.     else if (stance == CO_r) // On right wall.
  3959.       set_vel_next(vel + cc->acceleration * unitAccs[CO_r_UP]);
  3960.     else if (stance == CO_l) // On left wall.
  3961.       set_vel_next(vel + cc->acceleration * unitAccs[CO_l_UP]);
  3962.     else if (stance == CO_climb)
  3963.       set_vel_next(vel + cc->acceleration * unitAccs[CO_climb_UP]);
  3964.     break;
  3965.     
  3966.   case IT_UP_R:
  3967.     set_want_corner(CO_air);  
  3968.     if (stance == CO_r) // On right wall.
  3969.       {
  3970.     set_want_corner(CO_r_UP);
  3971.     set_vel_next(vel + cc->acceleration * unitAccs[CO_r_UP]);
  3972.       }
  3973.     else if ((stance == CO_dn) || (stance == CO_l) || (stance == CO_center) ||
  3974.          (stance == CO_climb)) 
  3975.       { /* Jump right. */
  3976.     set_vel_next(vel + cc->jump * unitAccs[CO_air_R]);
  3977.     set_stance_next(CO_air);
  3978.       }
  3979.     else if (stance == CO_up) // On ceiling.
  3980.       {
  3981.     set_want_corner(CO_up_R);
  3982.     set_vel_next(vel + cc->acceleration * unitAccs[CO_up_R]);
  3983.       }
  3984.     break;
  3985.   }
  3986.   
  3987.   // Go around outside corners. 
  3988.   if (want_corner(hanging.corner))
  3989.     {
  3990.       set_stance_next(cornered_stance(hanging));
  3991.       set_vel_next(0);
  3992.       corner(hanging);
  3993.       set_want_corner(CO_air);
  3994.     }
  3995. }
  3996.  
  3997.  
  3998.  
  3999. Boolean Sticky::want_corner(const Corner &corner)
  4000. {
  4001.   return (corner != CO_air) && 
  4002.     ((corner == wantCorner1) || (corner == wantCorner2));
  4003. }
  4004.  
  4005.  
  4006.  
  4007. Stance Sticky::cornered_stance(const Hanging &hanging)
  4008. {
  4009.   switch (hanging.corner) {
  4010.   case CO_r_DN:
  4011.     return CO_up;
  4012.   case CO_r_UP:
  4013.     return CO_dn;
  4014.   case CO_dn_R:
  4015.     return CO_l;
  4016.   case CO_dn_L:
  4017.     return CO_r;
  4018.   case CO_l_DN:
  4019.     return CO_up;
  4020.   case CO_l_UP:
  4021.     return CO_dn;
  4022.   case CO_up_R:
  4023.     return CO_l;
  4024.   case CO_up_L:
  4025.     return CO_r;
  4026.   default:
  4027.     assert(0);
  4028.     return CO_air;
  4029.   }
  4030. }
  4031.  
  4032.  
  4033.  
  4034. Flying::Flying(const FlyingContext &cx,FlyingXdata &)
  4035. {
  4036.   context = &cx;
  4037.   Timer nTimer(cx.gravTime);
  4038.   gravTimer = nTimer;
  4039. }
  4040.  
  4041.  
  4042.  
  4043. Boolean Flying::is_flying()
  4044. {
  4045.   return True;
  4046. }
  4047.  
  4048.  
  4049.  
  4050. void Flying::act() 
  4051. {
  4052.   _act(); 
  4053.   Creature::act();
  4054. }
  4055.  
  4056.  
  4057.  
  4058. void Flying::_act()
  4059. {
  4060.   // Methods of Moving or Creature.
  4061.   const CreatureContext *cc = get_creature_context();
  4062.   const Stance stance = get_stance();
  4063.   const Touching touchingArea = get_touching_area();
  4064.   const Touching touchingStance = get_touching_stance();
  4065.   const Vel vel = get_vel();
  4066.   const Acc *unitAccs = get_unit_accs();
  4067.   const ITcommand command = get_command(); 
  4068.   assert(stance == CO_air || stance == CO_center);
  4069.  
  4070.   /* Deal with gravity here instead of in Creature because falling less than
  4071.      one pixel per clock. */
  4072.   // Limits on velNext imposed by Creature.
  4073.   Vel velNext = vel;
  4074.   if (touchingArea != CO_dn && gravTimer.ready() && 
  4075.       vel.dy <= FLYING_GRAV_VEL_CUTOFF)
  4076.     {
  4077.       velNext.dy += 1;
  4078.       gravTimer.set();
  4079.     }
  4080.  
  4081.   if (touchingArea != touchingStance)
  4082.     {
  4083.       if (touchingArea == CO_dn)
  4084.     {
  4085.       set_stance_next(CO_center);
  4086.       velNext.dy = 0;
  4087.     }
  4088.       else if (touchingArea == CO_air)
  4089.     set_stance_next(CO_air);
  4090.     }  
  4091.  
  4092.   /* Interpret commands from controlling intelligence.  May override some of 
  4093.      above settings. */
  4094.   switch (command) {
  4095.   case IT_CENTER:
  4096.     velNext.set_zero();
  4097.     break;
  4098.  
  4099.   case IT_R:
  4100.     velNext = velNext + cc->acceleration * unitAccs[CO_R];
  4101.     break;
  4102.     
  4103.   case IT_DN_R:
  4104.     if (stance == CO_air)
  4105.       velNext = velNext + cc->acceleration * unitAccs[CO_DN_R];
  4106.     else
  4107.       velNext = velNext + cc->acceleration * unitAccs[CO_center_R];
  4108.     break;
  4109.     
  4110.   case IT_DN:
  4111.     if (stance == CO_air)
  4112.       velNext = velNext + cc->acceleration * unitAccs[CO_DN];
  4113.     else
  4114.       velNext.set_zero();
  4115.     break;
  4116.     
  4117.   case IT_DN_L:
  4118.     if (stance == CO_air)
  4119.       velNext = velNext + cc->acceleration * unitAccs[CO_DN_L];
  4120.     else
  4121.       velNext = velNext + cc->acceleration * unitAccs[CO_center_L];
  4122.     break;
  4123.     
  4124.   case IT_L:
  4125.     velNext = velNext + cc->acceleration * unitAccs[CO_L];
  4126.     break;
  4127.     
  4128.   case IT_UP_L:
  4129.     if (stance == CO_air)
  4130.       velNext = velNext + cc->acceleration * unitAccs[CO_air_L];
  4131.     else
  4132.       {
  4133.     velNext = velNext + cc->jump * unitAccs[CO_air_L];
  4134.     set_stance_next(CO_air);
  4135.       }
  4136.     break;
  4137.  
  4138.   case IT_UP:
  4139.     if (stance == CO_air)
  4140.       velNext = velNext + cc->acceleration * unitAccs[CO_air_UP];
  4141.     else
  4142.       {
  4143.     velNext = velNext + cc->jump * unitAccs[CO_air_UP];
  4144.     set_stance_next(CO_air);
  4145.       }
  4146.     break;
  4147.  
  4148.   case IT_UP_R:
  4149.     if (stance == CO_air)
  4150.       velNext = velNext + cc->acceleration * unitAccs[CO_air_R];
  4151.     else
  4152.       {
  4153.     velNext = velNext + cc->jump * unitAccs[CO_air_R];
  4154.     set_stance_next(CO_air);
  4155.       }
  4156.     break;
  4157.   };
  4158.  
  4159.   set_vel_next(velNext);
  4160.  
  4161.   gravTimer.clock();
  4162. }
  4163.  
  4164.  
  4165.  
  4166. BuiltIn::BuiltIn(const BuiltInContext &cx,BuiltInXdata &)
  4167. {
  4168.   Timer nTimer(cx.shotTime);
  4169.   shotTimer = nTimer;
  4170. }
  4171.  
  4172.  
  4173.  
  4174. Boolean BuiltIn::is_built_in()
  4175. {
  4176.   return True;
  4177. }
  4178.  
  4179.  
  4180.  
  4181. Boolean BuiltIn::ready()
  4182. {
  4183.   return shotTimer.ready();
  4184. }
  4185.  
  4186.  
  4187.  
  4188. void BuiltIn::act()
  4189. {
  4190.   _act();
  4191.   Creature::act();
  4192. }
  4193.  
  4194.  
  4195.  
  4196. void BuiltIn::_act()
  4197. {
  4198.   Dir shotDir;
  4199.   if (shotTimer.ready() && 
  4200.       (shotDir = Intel::command_weapon_to_dir_8(get_command())) != CO_air &&
  4201.       !get_weapon_current())
  4202.     {
  4203.       const Area &area = get_area();
  4204.       LocatorP locator = get_locator();
  4205.       Pos shotPos = area.adjacent_rect(get_shot_size(shotDir),shotDir);
  4206.       PhysicalP shot = create_shot(shotPos,shotDir);
  4207.       shot->set_dont_collide(this);
  4208.       locator->add(shot);
  4209.       shotTimer.set();
  4210.     } 
  4211.   
  4212.   shotTimer.clock();
  4213. }
  4214.